diff --git a/libWindbot/Game/AI/CardContainer.cs b/libWindbot/Game/AI/CardContainer.cs index bc69190..888e03f 100644 --- a/libWindbot/Game/AI/CardContainer.cs +++ b/libWindbot/Game/AI/CardContainer.cs @@ -55,28 +55,32 @@ public static ClientCard GetHighestAttackMonster(this IEnumerable ca { return cards .Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget())) - .OrderBy(card => card.Attack).FirstOrDefault(); + .OrderByDescending(card => card.Attack) + .FirstOrDefault(); } public static ClientCard GetHighestDefenseMonster(this IEnumerable cards, bool canBeTarget = false) { return cards .Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget())) - .OrderBy(card => card.Defense).FirstOrDefault(); + .OrderByDescending(card => card.Defense) + .FirstOrDefault(); } public static ClientCard GetLowestAttackMonster(this IEnumerable cards, bool canBeTarget = false) { return cards .Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget())) - .OrderByDescending(card => card.Attack).FirstOrDefault(); + .OrderBy(card => card.Attack) + .FirstOrDefault(); } public static ClientCard GetLowestDefenseMonster(this IEnumerable cards, bool canBeTarget = false) { return cards .Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget())) - .OrderByDescending(card => card.Defense).FirstOrDefault(); + .OrderBy(card => card.Defense) + .FirstOrDefault(); } public static bool ContainsMonsterWithLevel(this IEnumerable cards, int level) diff --git a/libWindbot/Game/AI/Decks/AlbazExecutor.cs b/libWindbot/Game/AI/Decks/AlbazExecutor.cs new file mode 100644 index 0000000..5ad4f57 --- /dev/null +++ b/libWindbot/Game/AI/Decks/AlbazExecutor.cs @@ -0,0 +1,5861 @@ +using YGOSharp.OCGWrapper; +using YGOSharp.OCGWrapper.Enums; +using System.Collections.Generic; +using System.Linq; +using System; +using WindBot; +using WindBot.Game; +using WindBot.Game.AI; + +namespace WindBot.Game.AI.Decks +{ + [Deck("Albaz", "AI_Albaz")] + public class AlbazExecutor : DefaultExecutor + { + public class CardId + { + public const int TheBystialLubellion = 32731036; + public const int AlbionTheShroudedDragon = 25451383; + public const int BystialSaronir = 60242223; + public const int AluberTheJesterOfDespia = 62962630; + public const int FallenOfAlbaz = 68468459; + public const int SpringansKitt = 45484331; + public const int GuidingQuemTheVirtuous = 45883110; + public const int BlazingCartesiaTheVirtuous = 95515789; + public const int TriBrigadeMercourier = 19096726; + // _CardId.AshBlossom = 14558127; + // _CardId.MaxxC = 23434538; + public const int DespianTragedy = 36577931; + + public const int NadirServant = 1984618; + public const int FusionDeployment = 6498706; + public const int BrandedInWhite = 34995106; + public const int BrandedFusion = 44362883; + public const int GoldSarcophagus = 75500286; + public const int FoolishBurial = 81439173; + // _CardId.CalledByTheGrave = 24224830; + public const int BrandedInHighSpirits = 29948294; + public const int BrandedOpening = 36637374; + // _CardId.CrossoutDesignator = 65681983; + public const int BrandedInRed = 82738008; + public const int BrandedLost = 18973184; + + // _CardId.InfiniteImpermanence = 10045474; + public const int BrightestBlazingBrandedKing = 19271881; + public const int BrandedBeast = 32756828; + public const int BrandedRetribution = 17751597; + + public const int GuardianChimera = 11321089; + public const int AlbionTheSanctifireDragon = 38811586; + public const int MirrorjadeTheIcebladeDragon = 44146295; + public const int BorreloadFuriousDragon = 92892239; + public const int LubellionTheSearingDragon = 70534340; + public const int AlbaLenatusTheAbyssDragon = 3410461; + public const int GranguignolTheDuskDragon = 24915933; + public const int DespianQuaeritis = 72272462; + public const int SprindTheIrondashDragon = 1906812; + public const int TitanikladTheAshDragon = 41373230; + public const int RindbrummTheStrikingDragon = 51409648; + public const int AlbionTheBrandedDragon = 87746184; + public const int DespianLuluwalilith = 53971455; + + public const int NaturalExterio = 99916754; + public const int NaturalBeast = 33198837; + public const int ImperialOrder = 61740673; + public const int SwordsmanLV7 = 37267041; + public const int RoyalDecree = 51452091; + public const int Number41BagooskatheTerriblyTiredTapir = 90590303; + public const int InspectorBoarder = 15397015; + public const int SkillDrain = 82732705; + + public const int DimensionShifter = 91800273; + public const int MacroCosmos = 30241314; + public const int DimensionalFissure = 81674782; + public const int BanisheroftheRadiance = 94853057; + public const int BanisheroftheLight = 61528025; + public const int KashtiraAriseHeart = 48626373; + public const int AccesscodeTalker = 86066372; + public const int GhostMournerMoonlitChill = 52038441; + public const int NibiruThePrimalBeing = 27204311; + } + + public AlbazExecutor(GameAI ai, Duel duel) + : base(ai, duel) + { + AddExecutor(ExecutorType.Activate, _CardId.MaxxC, MaxxCActivate); + + // + AddExecutor(ExecutorType.Summon, AdvanceSummon); + AddExecutor(ExecutorType.SpSummon, CardId.AlbaLenatusTheAbyssDragon, AlbaLenatusTheAbyssDragonSpSummon); + AddExecutor(ExecutorType.MonsterSet, CardId.FallenOfAlbaz, FallenOfAlbazSet); + AddExecutor(ExecutorType.Activate, CardId.BlazingCartesiaTheVirtuous, BlazingCartesiaTheVirtuousActivateInGrave); + + // quick effect + AddExecutor(ExecutorType.Activate, CardId.BrandedRetribution, BrandedRetributionActivate); + AddExecutor(ExecutorType.Activate, _CardId.CalledByTheGrave, CalledbytheGraveActivate); + AddExecutor(ExecutorType.Activate, _CardId.CrossoutDesignator, CrossoutDesignatorActivate); + AddExecutor(ExecutorType.Activate, _CardId.InfiniteImpermanence, InfiniteImpermanenceActivate); + AddExecutor(ExecutorType.Activate, _CardId.AshBlossom, AshBlossomActivate); + AddExecutor(ExecutorType.Activate, CardId.BrandedBeast, BrandedBeastActivate); + AddExecutor(ExecutorType.Activate, CardId.BrightestBlazingBrandedKing, BrightestBlazingBrandedKingActivate); + AddExecutor(ExecutorType.Activate, CardId.BrandedOpening, BrandedOpeningActivate); + AddExecutor(ExecutorType.Activate, CardId.BrandedInHighSpirits, BrandedInHighSpiritsActivate); + AddExecutor(ExecutorType.Activate, CardId.RindbrummTheStrikingDragon, RindbrummTheStrikingDragonActivate); + + // remove + AddExecutor(ExecutorType.Activate, CardId.GuardianChimera, GuardianChimeraActivate); + AddExecutor(ExecutorType.Activate, CardId.BorreloadFuriousDragon, BorreloadFuriousDragonActivate); + AddExecutor(ExecutorType.Activate, CardId.TriBrigadeMercourier, TriBrigadeMercourierActivate); + AddExecutor(ExecutorType.Activate, CardId.DespianQuaeritis, DespianQuaeritisActivate); + AddExecutor(ExecutorType.Activate, CardId.MirrorjadeTheIcebladeDragon, MirrorjadeTheIcebladeDragonActivate); + + // search + AddExecutor(ExecutorType.Activate, CardId.TheBystialLubellion, TheBystialLubellionActivate); + AddExecutor(ExecutorType.SpSummon, CardId.TheBystialLubellion, TheBystialLubellionSpSummon); + AddExecutor(ExecutorType.Activate, CardId.FoolishBurial, FoolishBurialActivate); + AddExecutor(ExecutorType.Activate, CardId.GoldSarcophagus, GoldSarcophagusActivate); + AddExecutor(ExecutorType.Activate, CardId.AluberTheJesterOfDespia, AluberTheJesterOfDespiaActivate); + + AddExecutor(ExecutorType.Activate, CardId.AlbionTheSanctifireDragon, AlbionTheSanctifireDragonActivate); + + // blazing + AddExecutor(ExecutorType.Activate, CardId.FusionDeployment, FusionDeploymentActivate); + + AddExecutor(ExecutorType.Activate, CardId.AlbionTheShroudedDragon, AlbionTheShroudedDragonActivate); + AddExecutor(ExecutorType.Activate, CardId.BystialSaronir, BystialSaronirActivate); + + // summon for search + AddExecutor(ExecutorType.Summon, CardId.AluberTheJesterOfDespia, AluberTheJesterOfDespiaSummon); + AddExecutor(ExecutorType.Summon, CardId.GuidingQuemTheVirtuous, GuidingQuemTheVirtuousSummonForSearch); + AddExecutor(ExecutorType.Activate, CardId.SpringansKitt, SpringansKittActivate); + AddExecutor(ExecutorType.Summon, CardId.SpringansKitt, SpringansKittSummon); + + // fusion & lost + AddExecutor(ExecutorType.Activate, CardId.BrandedLost, BrandedLostCardActivate); + AddExecutor(ExecutorType.Activate, CardId.GranguignolTheDuskDragon, GranguignolTheDuskDragonActivate); + AddExecutor(ExecutorType.Activate, CardId.AlbaLenatusTheAbyssDragon, AlbaLenatusTheAbyssDragonActivate); + AddExecutor(ExecutorType.Activate, CardId.SprindTheIrondashDragon, SprindTheIrondashDragonActivate); + AddExecutor(ExecutorType.Activate, CardId.TitanikladTheAshDragon, TitanikladTheAshDragonActivate); + AddExecutor(ExecutorType.Activate, CardId.AlbionTheBrandedDragon, AlbionTheBrandedDragonActivate); + AddExecutor(ExecutorType.Activate, CardId.LubellionTheSearingDragon, LubellionTheSearingDragonActivate); + AddExecutor(ExecutorType.Summon, CardId.BlazingCartesiaTheVirtuous, BlazingCartesiaTheVirtuousSummon); + AddExecutor(ExecutorType.Activate, CardId.FallenOfAlbaz, FallenOfAlbazActivate); + AddExecutor(ExecutorType.Activate, CardId.BrandedFusion, BrandedFusionActivate); + AddExecutor(ExecutorType.Activate, CardId.BlazingCartesiaTheVirtuous, BlazingCartesiaTheVirtuousActivate); + AddExecutor(ExecutorType.Activate, CardId.BrandedInWhite, BrandedInWhiteActivate); + AddExecutor(ExecutorType.Activate, CardId.BrandedInRed, BrandedInRedActivate); + AddExecutor(ExecutorType.Activate, CardId.BrandedLost, BrandedLostActivate); + + // albaz summon + AddExecutor(ExecutorType.Summon, CardId.FallenOfAlbaz, FallenOfAlbazSummon); + AddExecutor(ExecutorType.Summon, CardId.GuidingQuemTheVirtuous, GuidingQuemTheVirtuousSummon); + + // delay + AddExecutor(ExecutorType.Activate, CardId.DespianTragedy, DespianTragedyActivate); + AddExecutor(ExecutorType.Activate, CardId.TriBrigadeMercourier, TriBrigadeMercourierActivateForSearch); + AddExecutor(ExecutorType.Activate, CardId.NadirServant, NadirServantActivate); + + AddExecutor(ExecutorType.MonsterSet, SetForChimera); + AddExecutor(ExecutorType.MonsterSet, CardId.DespianTragedy, DespianTragedySet); + AddExecutor(ExecutorType.Repos, DefaultMonsterRepos); + AddExecutor(ExecutorType.SpellSet, SpellSetCheck); + AddExecutor(ExecutorType.Activate, CardId.GuidingQuemTheVirtuous, GuidingQuemTheVirtuousActivate); + AddExecutor(ExecutorType.Activate, CardId.DespianLuluwalilith, DespianLuluwalilithActivate); + + AddExecutor(ExecutorType.Activate, FloogateActivate); + + } + + const int SetcodeTimeLord = 0x4a; + const int SetcodePhantom = 0xdb; + const int SetcodeOrcust = 0x11b; + const int SetcodeBranded = 0x15d; + const int SetcodeDespain = 0x164; + const int SetcodeBystial = 0x188; + const int SetcodeHorus = 0x19d; + const int hintTimingMainEnd = 0x4; + const int hintBattleStart = 0x8; + List notToNegateIdList = new List{ + 58699500, 20343502, CardId.AlbionTheShroudedDragon, 19403423 + }; + List cannotBeFusionMaterialIdList = new List + { + CardId.AlbaLenatusTheAbyssDragon, CardId.AlbionTheSanctifireDragon, 79229522, 65029288, 30864377, 33964637, 87116928, 13735899, 28226490, 80453041, + _CardId.EaterOfMillions, 2992467, 16366810, 40217358, 47346782, 50893987, 71459017, 84433295, 85101097 + }; + List albazFusionMonster = new List + { + CardId.TitanikladTheAshDragon, CardId.SprindTheIrondashDragon, CardId.AlbionTheBrandedDragon, CardId.LubellionTheSearingDragon, CardId.AlbaLenatusTheAbyssDragon, + CardId.MirrorjadeTheIcebladeDragon, CardId.RindbrummTheStrikingDragon, CardId.AlbionTheSanctifireDragon + }; + Dictionary> DeckCountTable = new Dictionary>{ + {3, new List { CardId.AluberTheJesterOfDespia, _CardId.AshBlossom, _CardId.MaxxC, _CardId.InfiniteImpermanence }}, + {2, new List { CardId.FallenOfAlbaz, CardId.NadirServant, CardId.FusionDeployment, _CardId.CalledByTheGrave }}, + {1, new List { CardId.TheBystialLubellion, CardId.AlbionTheShroudedDragon, CardId.BystialSaronir, CardId.SpringansKitt, CardId.GuidingQuemTheVirtuous, + CardId.BlazingCartesiaTheVirtuous, CardId.TriBrigadeMercourier, CardId.DespianTragedy, CardId.BrandedInWhite, + CardId.BrandedFusion, CardId.GoldSarcophagus, CardId.FoolishBurial, CardId.BrandedInHighSpirits, CardId.BrandedOpening, + _CardId.CrossoutDesignator, CardId.BrandedInRed, CardId.BrandedLost, CardId.BrightestBlazingBrandedKing, + CardId.BrandedBeast, CardId.BrandedRetribution }} + }; + List dangerousDragonIdList = new List { 27548199, 92892239, 98630720, 9753964, 99585850, 24361622, 27572350, 69120785, 96402918, 74294676, 42752141, 18511599, 35103106, 26268488 }; + List notToDestroySpellTrap = new List { 50005218, 6767771 }; + List targetNegateIdList = new List { + _CardId.EffectVeiler, _CardId.InfiniteImpermanence, CardId.GhostMournerMoonlitChill, _CardId.BreakthroughSkill, 74003290, 67037924, + 9753964, 66192538, 23204029, 73445448, 35103106, 30286474, 45002991, 5795980, 38511382, 53742162, 30430448 + }; + + bool summoned = false; + bool enemyActivateMaxxC = false; + bool enemyActivateLockBird = false; + int dimensionShifterCount = 0; + bool enemyActivateInfiniteImpermanenceFromHand = false; + bool theBystialLubellionSelecting = false; + bool albionTheShroudedDragonSelecting = false; + bool nadirActivated = false; + bool fusionToGYFlag = false; + bool spSummoningAlbaz = false; + int cartesiaSummonGoal = 0; + int sanctifireSelectPositionCount = 0; + int quemSummonFlag = 0; + List cartesiaMaterialList = new List(); + List brandedInRedMaterialList = new List(); + List infiniteImpermanenceList = new List(); + List currentNegateCardList = new List(); + List currentDestroyCardList = new List(); + List sendToGYThisTurn = new List(); + List activatedCardIdList = new List(); + ClientCard fusionTarget = null; + List selectedFusionMaterial = new List(); + List enemyPlaceThisTurn = new List(); + + /// + /// Shuffle List and return a random-order card list + /// + public List ShuffleList(List list) + { + List result = list; + int n = result.Count; + while (n-- > 1) + { + int index = Program.Rand.Next(result.Count); + int nextIndex = (index + Program.Rand.Next(result.Count - 1)) % result.Count; + T tempCard = result[index]; + result[index] = result[nextIndex]; + result[nextIndex] = tempCard; + } + return result; + } + + public bool CheckCanBeTargeted(ClientCard card, bool canBeTarget, CardType selfType) + { + if (card == null) return true; + if (canBeTarget) + { + if (card.IsShouldNotBeTarget()) return false; + if (((int)selfType & (int)CardType.Monster) > 0 && card.IsShouldNotBeMonsterTarget()) return false; + if (((int)selfType & (int)CardType.Spell) > 0 && card.IsShouldNotBeSpellTrapTarget()) return false; + if (((int)selfType & (int)CardType.Trap) > 0 + && (card.IsShouldNotBeSpellTrapTarget() && !card.IsDisabled())) return false; + } + return true; + } + + /// + /// Check remain cards in deck + /// + /// Card's ID + public int CheckRemainInDeck(int id) + { + for (int count = 1; count < 4; ++count) + { + if (DeckCountTable[count].Contains(id)) { + return Bot.GetRemainingCount(id, count); + } + } + return 0; + } + + public int CheckRemainInDeck(params int[] ids) + { + int sum = 0; + foreach (int id in ids) + { + sum += CheckRemainInDeck(id); + } + return sum; + } + + /// + /// Check whether'll be negated + /// + /// check whether card itself is disabled. + public bool CheckWhetherNegated(bool disablecheck = true, bool toFieldCheck = false, CardType type = 0) + { + bool isMonster = type == 0 && Card.IsMonster(); + isMonster |= ((int)type & (int)CardType.Monster) != 0; + bool isSpellOrTrap = type == 0 && (Card.IsSpell() || Card.IsTrap()); + isSpellOrTrap |= (((int)type & (int)CardType.Spell) != 0) || (((int)type & (int)CardType.Trap) != 0); + bool isCounter = ((int)type & (int)CardType.Counter) != 0; + if (isSpellOrTrap && toFieldCheck && CheckSpellWillBeNegate(isCounter)) + return true; + if (DefaultCheckWhetherCardIsNegated(Card)) return true; + if (isMonster && (toFieldCheck || Card.Location == CardLocation.MonsterZone)) + { + if ((toFieldCheck && (((int)type & (int)CardType.Link) != 0)) || Card.IsDefense()) + { + if (Enemy.MonsterZone.Any(card => CheckNumber41(card)) || Bot.MonsterZone.Any(card => CheckNumber41(card))) return true; + } + if (Enemy.HasInSpellZone(CardId.SkillDrain, true, true)) return true; + } + if (disablecheck) return (Card.Location == CardLocation.MonsterZone || Card.Location == CardLocation.SpellZone) && Card.IsDisabled() && Card.IsFaceup(); + return false; + } + + public bool CheckNumber41(ClientCard card) + { + return card != null && card.IsFaceup() && card.IsCode(CardId.Number41BagooskatheTerriblyTiredTapir) && card.IsDefense() && !card.IsDisabled(); + } + + /// + /// Whether spell or trap will be negate. If so, return true. + /// + /// is counter trap + /// check target + /// + public bool CheckSpellWillBeNegate(bool isCounter = false, ClientCard target = null) + { + // target default set + if (target == null) target = Card; + // won't negate if not on field + if (target.Location != CardLocation.SpellZone && target.Location != CardLocation.Hand) return false; + + // negate judge + if (Enemy.HasInMonstersZone(CardId.NaturalExterio, true) && !isCounter) return true; + if (target.IsSpell()) + { + if (Enemy.HasInMonstersZone(CardId.NaturalBeast, true)) return true; + if (Enemy.HasInSpellZone(CardId.ImperialOrder, true) || Bot.HasInSpellZone(CardId.ImperialOrder, true)) return true; + if (Enemy.HasInMonstersZone(CardId.SwordsmanLV7, true) || Bot.HasInMonstersZone(CardId.SwordsmanLV7, true)) return true; + } + if (target.IsTrap() && (Enemy.HasInSpellZone(CardId.RoyalDecree, true) || Bot.HasInSpellZone(CardId.RoyalDecree, true))) return true; + if (target.Location == CardLocation.SpellZone && (target.IsSpell() || target.IsTrap())) + { + int selfSeq = -1; + for (int i = 0; i < 5; ++i) + { + if (Bot.SpellZone[i] == Card) selfSeq = i; + } + if (infiniteImpermanenceList.Contains(selfSeq)) return true; + } + // how to get here? + return false; + } + + /// + /// Check whether last chain card should be disabled. + /// + public bool CheckLastChainShouldNegated() + { + ClientCard lastcard = Util.GetLastChainCard(); + if (lastcard == null || lastcard.Controller != 1) return false; + if (lastcard.IsMonster() && lastcard.HasSetcode(SetcodeTimeLord) && Duel.Phase == DuelPhase.Standby) return false; + if (notToNegateIdList.Contains(lastcard.Id)) return false; + if (DefaultCheckWhetherCardIsNegated(lastcard)) return false; + if (Duel.Turn == 1 && lastcard.IsCode(_CardId.MaxxC)) return false; + + return true; + } + + /// + /// Check whether bot is at advantage. + /// + public bool CheckAtAdvantage() + { + if (GetProblematicEnemyMonster() == null && (Duel.Player == 0 || Bot.GetMonsterCount() > 0)) return true; + return false; + } + + public bool CheckShouldNoMoreSpSummon() + { + if (CheckAtAdvantage() && enemyActivateMaxxC && !enemyActivateLockBird && (Duel.Turn == 1 || Duel.Phase >= DuelPhase.Main2)) + { + return true; + } + return false; + } + + public bool CheckWhetherCanSummon() + { + return Duel.Player == 0 && Duel.Phase < DuelPhase.End && !summoned; + } + + /// + /// Check whether cards will be removed. If so, do not send cards to grave. + /// + public bool CheckWhetherWillbeRemoved() + { + if (dimensionShifterCount > 0) return true; + List checkIdList = new List { CardId.BanisheroftheRadiance, CardId.BanisheroftheLight, CardId.MacroCosmos, CardId.DimensionalFissure, + CardId.KashtiraAriseHeart, 58481572 }; + foreach (int cardid in checkIdList) + { + List fields = new List { Bot, Enemy }; + foreach (ClientField cf in fields) + { + if (cf.HasInMonstersZone(cardid, true, false, true) || cf.HasInSpellZone(cardid, true, true)) + { + return true; + } + } + } + return false; + } + + /// + /// Check whether it should be kept in grave to activate effect. + /// If should, return true. + /// + /// + /// + public bool CheckWhetherShouldKeepInGrave(ClientCard c) + { + if (c.IsCode(CardId.GranguignolTheDuskDragon) && c.Location == CardLocation.Grave) return true; + if (!c.IsCode(new int[] { CardId.AlbaLenatusTheAbyssDragon, CardId.AlbionTheBrandedDragon, CardId.TitanikladTheAshDragon, CardId.DespianLuluwalilith, + CardId.SprindTheIrondashDragon})) + { + return false; + } + return sendToGYThisTurn.Contains(c) && c.Location == CardLocation.Grave; + } + + public ClientCard GetProblematicEnemyMonster(int attack = 0, bool canBeTarget = false, bool ignoreCurrentDestroy = false, CardType selfType = 0) + { + ClientCard floodagateCard = Enemy.GetMonsters().Where(c => c?.Data != null && (ignoreCurrentDestroy || !currentDestroyCardList.Contains(c)) + && c.IsFloodgate() && c.IsFaceup() + && CheckCanBeTargeted(c, canBeTarget, selfType) + && CheckShouldNotIgnore(c)).OrderByDescending(card => card.Attack).FirstOrDefault(); + if (floodagateCard != null) return floodagateCard; + + ClientCard dangerCard = Enemy.MonsterZone.Where(c => c?.Data != null && (ignoreCurrentDestroy || !currentDestroyCardList.Contains(c)) + && c.IsMonsterDangerous() && c.IsFaceup() && CheckCanBeTargeted(c, canBeTarget, selfType) + && CheckShouldNotIgnore(c)).OrderByDescending(card => card.Attack).FirstOrDefault(); + if (dangerCard != null) return dangerCard; + + ClientCard invincibleCard = Enemy.MonsterZone.Where(c => c?.Data != null && (ignoreCurrentDestroy || !currentDestroyCardList.Contains(c)) + && c.IsMonsterInvincible() && c.IsFaceup() && CheckCanBeTargeted(c, canBeTarget, selfType) + && CheckShouldNotIgnore(c)).OrderByDescending(card => card.Attack).FirstOrDefault(); + if (invincibleCard != null) return invincibleCard; + + ClientCard equippedCard = Enemy.MonsterZone.Where(c => c?.Data != null && (ignoreCurrentDestroy || !currentDestroyCardList.Contains(c)) + && c.EquipCards.Count > 0 && CheckCanBeTargeted(c, canBeTarget, selfType) + && CheckShouldNotIgnore(c)).OrderByDescending(card => card.Attack).FirstOrDefault(); + if (equippedCard != null) return equippedCard; + + ClientCard enemyExtraMonster = Enemy.MonsterZone.Where(c => c != null && (ignoreCurrentDestroy || !currentDestroyCardList.Contains(c)) + && (c.HasType(CardType.Fusion | CardType.Ritual | CardType.Synchro | CardType.Xyz) || (c.HasType(CardType.Link) && c.LinkCount >= 2)) + && CheckCanBeTargeted(c, canBeTarget, selfType) && CheckShouldNotIgnore(c)).OrderByDescending(card => card.Attack).FirstOrDefault(); + if (enemyExtraMonster != null) return enemyExtraMonster; + + ClientCard activatingAlbaz = Enemy.MonsterZone.FirstOrDefault(c => c != null && c.IsCode(CardId.FallenOfAlbaz) && !c.IsDisabled() + && !currentDestroyCardList.Contains(c) && !currentNegateCardList.Contains(c) && Duel.CurrentChain.Contains(c)); + if (activatingAlbaz != null) return activatingAlbaz; + + if (attack >= 0) + { + if (attack == 0) + attack = Util.GetBestAttack(Bot); + ClientCard betterCard = Enemy.MonsterZone.Where(card => card != null + && card.GetDefensePower() >= attack && card.GetDefensePower() > 0 && card.IsAttack() && CheckCanBeTargeted(card, canBeTarget, selfType) + && (ignoreCurrentDestroy || !currentDestroyCardList.Contains(card))).OrderByDescending(card => card.Attack).FirstOrDefault(); + if (betterCard != null) return betterCard; + } + return null; + } + + public bool CheckShouldNotIgnore(ClientCard cards, bool ignore = false) + { + return !ignore || (!currentDestroyCardList.Contains(cards) && !currentNegateCardList.Contains(cards)); + } + + /// + /// check enemy's dangerous card in grave + /// + public List GetDangerousCardinEnemyGrave(bool onlyMonster = false) + { + List result = Enemy.Graveyard.GetMatchingCards(card => + (!onlyMonster || card.IsMonster()) && (card.HasSetcode(SetcodeOrcust) || card.HasSetcode(SetcodePhantom) || card.HasSetcode(SetcodeHorus))).ToList(); + List dangerMonsterIdList = new List{ + 99937011, 63542003, 9411399, 28954097, 30680659 + }; + result.AddRange(Enemy.Graveyard.GetMatchingCards(card => dangerMonsterIdList.Contains(card.Id))); + return result; + } + + public List GetProblematicEnemyCardList(bool canBeTarget = false, bool ignoreSpells = false, CardType selfType = 0) + { + List resultList = new List(); + + List floodagateList = Enemy.MonsterZone.Where(c => c?.Data != null && !currentDestroyCardList.Contains(c) + && c.IsFloodgate() && c.IsFaceup() && CheckCanBeTargeted(c, canBeTarget, selfType)).OrderByDescending(card => card.Attack).ToList(); + if (floodagateList.Count > 0) resultList.AddRange(floodagateList); + + List problemEnemySpellList = Enemy.SpellZone.Where(c => c?.Data != null && !resultList.Contains(c) && !currentDestroyCardList.Contains(c) + && c.IsFloodgate() && c.IsFaceup() && CheckCanBeTargeted(c, canBeTarget, selfType)).ToList(); + if (problemEnemySpellList.Count > 0) resultList.AddRange(ShuffleList(problemEnemySpellList)); + + List dangerList = Enemy.MonsterZone.Where(c => c?.Data != null && !resultList.Contains(c) && !currentDestroyCardList.Contains(c) + && c.IsMonsterDangerous() && c.IsFaceup() && CheckCanBeTargeted(c, canBeTarget, selfType)).OrderByDescending(card => card.Attack).ToList(); + if (dangerList.Count > 0 + && (Duel.Player == 0 || (Duel.Phase > DuelPhase.Main1 && Duel.Phase < DuelPhase.Main2))) resultList.AddRange(dangerList); + + List invincibleList = Enemy.MonsterZone.Where(c => c?.Data != null && !resultList.Contains(c) && !currentDestroyCardList.Contains(c) + && c.IsMonsterInvincible() && c.IsFaceup() && CheckCanBeTargeted(c, canBeTarget, selfType)).OrderByDescending(card => card.Attack).ToList(); + if (invincibleList.Count > 0) resultList.AddRange(invincibleList); + + List enemyMonsters = Enemy.GetMonsters().Where(c => !currentDestroyCardList.Contains(c)).OrderByDescending(card => card.Attack).ToList(); + if (enemyMonsters.Count > 0) + { + foreach (ClientCard target in enemyMonsters) + { + if ((target.HasType(CardType.Fusion | CardType.Ritual | CardType.Synchro | CardType.Xyz) + || (target.HasType(CardType.Link) && target.LinkCount >= 2)) + && !resultList.Contains(target) && CheckCanBeTargeted(target, canBeTarget, selfType) + ) + { + resultList.Add(target); + } + } + } + + List spells = Enemy.GetSpells().Where(c => c.IsFaceup() && !currentDestroyCardList.Contains(c) + && c.HasType(CardType.Equip | CardType.Pendulum | CardType.Field | CardType.Continuous) && CheckCanBeTargeted(c, canBeTarget, selfType) + && !notToDestroySpellTrap.Contains(c.Id)).ToList(); + if (spells.Count > 0 && !ignoreSpells) resultList.AddRange(ShuffleList(spells)); + + return resultList; + } + + public List GetNormalEnemyTargetList(bool canBeTarget = true, bool ignoreCurrentDestroy = false, CardType selfType = 0) + { + List targetList = GetProblematicEnemyCardList(canBeTarget, selfType: selfType); + List enemyMonster = Enemy.GetMonsters().Where(card => card.IsFaceup() && !targetList.Contains(card) + && (!ignoreCurrentDestroy || !currentDestroyCardList.Contains(card))).ToList(); + enemyMonster.Sort(CardContainer.CompareCardAttack); + enemyMonster.Reverse(); + targetList.AddRange(enemyMonster); + targetList.AddRange(ShuffleList(Enemy.GetSpells().Where(card => + (!ignoreCurrentDestroy || !currentDestroyCardList.Contains(card)) && enemyPlaceThisTurn.Contains(card)).ToList())); + targetList.AddRange(ShuffleList(Enemy.GetSpells().Where(card => + (!ignoreCurrentDestroy || !currentDestroyCardList.Contains(card)) && !enemyPlaceThisTurn.Contains(card)).ToList())); + targetList.AddRange(ShuffleList(Enemy.GetMonsters().Where(card => card.IsFacedown() && (!ignoreCurrentDestroy || !currentDestroyCardList.Contains(card))).ToList())); + + return targetList; + } + + public List GetMonsterListForTargetNegate(bool canBeTarget = false, CardType selfType = 0) + { + List resultList = new List(); + if (CheckWhetherNegated()) + { + return resultList; + } + + // negate before used + ClientCard target = Enemy.MonsterZone.FirstOrDefault(card => card?.Data != null + && card.IsMonsterShouldBeDisabledBeforeItUseEffect() && card.IsFaceup() && !card.IsShouldNotBeTarget() + && CheckCanBeTargeted(card, canBeTarget, selfType) + && !currentNegateCardList.Contains(card)); + if (target != null) + { + resultList.Add(target); + } + + // negate monster effect on the field + foreach (ClientCard chainingCard in Duel.CurrentChain) + { + if (chainingCard.Location == CardLocation.MonsterZone && chainingCard.Controller == 1 && !chainingCard.IsDisabled() + && CheckCanBeTargeted(chainingCard, canBeTarget, selfType) && !currentNegateCardList.Contains(chainingCard)) + { + resultList.Add(chainingCard); + } + } + + return resultList; + } + + public override BattlePhaseAction OnBattle(IList attackers, IList defenders) + { + if (attackers.Count() > 0 && defenders.Count() > 0) + { + List sortedAttacker = attackers.OrderBy(card => card.Attack).ToList(); + ClientCard abyssDragon = attackers.FirstOrDefault(c => c.IsCode(CardId.AlbaLenatusTheAbyssDragon) && !c.IsDisabled()); + if (abyssDragon != null) + { + sortedAttacker.Remove(abyssDragon); + sortedAttacker.Insert(0, abyssDragon); + } + for (int k = 0; k < sortedAttacker.Count; ++k) + { + ClientCard attacker = sortedAttacker[k]; + attacker.IsLastAttacker = k == sortedAttacker.Count - 1; + BattlePhaseAction result = OnSelectAttackTarget(attacker, defenders); + if (result != null) + return result; + } + } + + return base.OnBattle(attackers, defenders); + } + + /// + /// go first + /// + public override bool OnSelectHand() + { + return true; + } + + public override IList OnSelectCard(IList cards, int min, int max, int hint, bool cancelable) + { + ClientCard currentSolvingChain = Duel.GetCurrentSolvingChainCard(); + if (currentSolvingChain != null) + { + if (currentSolvingChain.Controller == 1 && currentSolvingChain.IsCode(_CardId.EvenlyMatched)) + { + Logger.DebugWriteLine("=== Evenly Matched activated."); + List banishList = new List(); + List botMonsters = Bot.GetMonsters().Where(card => !card.HasType(CardType.Token)).ToList(); + + // monster + List faceDownMonsters = botMonsters.Where(card => card.IsFacedown()).ToList(); + banishList.AddRange(faceDownMonsters); + List dumpMainMonsterList = botMonsters.Where(card => !banishList.Contains(card) + && CheckRemainInDeck(card.Id) > 0).ToList(); + dumpMainMonsterList.Sort(CardContainer.CompareCardAttack); + banishList.AddRange(dumpMainMonsterList); + + // spells + List faceUpSpells = Bot.GetSpells().Where(c => c.IsFaceup()).ToList(); + banishList.AddRange(ShuffleList(faceUpSpells)); + List faceDownSpells = Bot.GetSpells().Where(c => c.IsFacedown()).ToList(); + banishList.AddRange(ShuffleList(faceDownSpells)); + + List uniqueMainMonster = botMonsters.Where(card => !banishList.Contains(card) + && !card.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link) && CheckRemainInDeck(card.Id) == 0).ToList(); + uniqueMainMonster.Sort(CardContainer.CompareCardAttack); + banishList.AddRange(uniqueMainMonster); + + List dumpExtraMonsterList = botMonsters.Where(card => !banishList.Contains(card) + && card.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link) && Bot.HasInExtra(card.Id)).ToList(); + dumpExtraMonsterList.Sort(CardContainer.CompareCardAttack); + banishList.AddRange(dumpExtraMonsterList); + + List uniqueExtraMonsterList = botMonsters.Where(card => !banishList.Contains(card) + && card.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link) && !Bot.HasInExtra(card.Id)).ToList(); + uniqueExtraMonsterList.Sort(CardContainer.CompareCardAttack); + banishList.AddRange(uniqueExtraMonsterList); + + return Util.CheckSelectCount(banishList, cards, min, max); + } + + // search operation + if (hint == HintMsg.AddToHand) + { + Dictionary> checkDict = new Dictionary>(); + + switch (currentSolvingChain.Id) + { + case CardId.AluberTheJesterOfDespia: + case CardId.AluberTheJesterOfDespia + 1: + case CardId.SpringansKitt: + checkDict = new Dictionary> { + {CardId.BrandedFusion, () => BrandedFusionActivateCheck()}, + {CardId.BrandedLost, () => { + if (Duel.Player == 0 && Duel.Phase >= DuelPhase.End) return false; + if (Bot.HasInHandOrInSpellZone(CardId.BrandedFusion) && BrandedFusionActivateCheck()) return true; + if (Bot.HasInHandOrInSpellZone(CardId.BrandedInWhite) && BrandedInWhiteActivateCheck()) return true; + if (Bot.HasInHandOrInSpellZone(CardId.BrandedInRed) && BrandedInRedActivateCheck() != null) return true; + if (!summoned && Bot.HasInHand(CardId.FallenOfAlbaz) && CheckAlbazFusion()) return true; + if ((Bot.HasInMonstersZone(CardId.BlazingCartesiaTheVirtuous) || (!summoned && Bot.HasInHand(CardId.BlazingCartesiaTheVirtuous)))) return true; + return false; + } + }, + {CardId.BrandedInHighSpirits, BrandedInHighSpiritsActivateCheck}, + {CardId.BrandedInRed, () => (Duel.Phase == DuelPhase.End && nadirActivated) || BrandedInRedActivateCheck() != null }, + {CardId.BrandedInWhite, BrandedInWhiteActivateCheck }, + {CardId.BrandedRetribution, () => cards.Any(c => c.IsCode(CardId.BrandedRetribution) && c.Location == CardLocation.Removed) }, + {CardId.BrightestBlazingBrandedKing, () => Bot.GetMonsters().Any(c => c.IsFaceup() && c.IsCode(albazFusionMonster)) }, + {CardId.BrandedOpening, () => Bot.Hand.Count > 2 } + }; + break; + case CardId.NadirServant: + if (!summoned) + { + ClientCard quem = cards.FirstOrDefault(c => c.IsCode(CardId.GuidingQuemTheVirtuous)); + if (quem != null) + { + return Util.CheckSelectCount(new List { quem }, cards, min, max); + } + } + List locList = new List { CardLocation.Grave, CardLocation.Deck }; + if (Bot.HasInGraveyard(CardId.RindbrummTheStrikingDragon) && cards.Where(c => c.IsOriginalCode(CardId.FallenOfAlbaz) && c.Location == CardLocation.Grave).Count() == 1) + { + locList = new List { CardLocation.Deck, CardLocation.Grave }; + } + foreach (int checkId in new[] { CardId.FallenOfAlbaz, CardId.GuidingQuemTheVirtuous }) + { + foreach (CardLocation loc in locList) + { + ClientCard target = cards.FirstOrDefault(c => c.IsOriginalCode(checkId) && c.Location == loc); + if (target != null) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + break; + case CardId.BrandedLost: + case CardId.TriBrigadeMercourier: + case CardId.BrandedInHighSpirits: + checkDict = new Dictionary>{ + {CardId.TriBrigadeMercourier, () => Bot.GetMonsters().Any(c => c.IsFaceup() && c.IsCode(albazFusionMonster)) + || (Bot.HasInMonstersZone(CardId.BlazingCartesiaTheVirtuous) && Bot.HasInHandOrHasInMonstersZone(CardId.FallenOfAlbaz))}, + {CardId.SpringansKitt, () => CheckWhetherCanSummon() && !activatedCardIdList.Contains(CardId.SpringansKitt + 1) }, + {CardId.FallenOfAlbaz, () => (CheckWhetherCanSummon() && CheckAlbazFusion()) || Bot.HasInMonstersZone(CardId.BlazingCartesiaTheVirtuous) }, + {CardId.GuidingQuemTheVirtuous, () => CheckWhetherCanSummon() }, + {CardId.BlazingCartesiaTheVirtuous, () => CheckWhetherCanSummon() || (!CheckShouldNoMoreSpSummon() && Bot.HasInMonstersZoneOrInGraveyard(CardId.FallenOfAlbaz))}, + {CardId.AlbionTheShroudedDragon, () => !CheckWhetherWillbeRemoved() && !activatedCardIdList.Contains(CardId.AlbionTheShroudedDragon) }, + }; + break; + case CardId.AlbaLenatusTheAbyssDragon: + checkDict = new Dictionary>{ + {CardId.BrandedFusion, () => BrandedFusionActivateCheck(false)}, + {CardId.FusionDeployment, () => true} + }; + break; + default: + break; + } + + foreach (KeyValuePair> pair in checkDict) + { + ClientCard target = cards.FirstOrDefault(card => card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + + switch (currentSolvingChain.Id) + { + // for lubellion + case CardId.TheBystialLubellion: + { + Dictionary> lubellionCheckDict = new Dictionary>(); + if (hint == HintMsg.ToField) + { + lubellionCheckDict.Add(CardId.BrandedLost, () => { + bool fusionFlag = Bot.HasInHandOrHasInMonstersZone(CardId.BlazingCartesiaTheVirtuous); + if (!activatedCardIdList.Contains(CardId.BrandedFusion)) + { + if (Bot.HasInHand(CardId.BrandedFusion) || (!summoned && CheckRemainInDeck(CardId.BrandedFusion) > 0 && Bot.HasInHand(new int[] { + CardId.AluberTheJesterOfDespia, CardId.SpringansKitt + }))) + { + fusionFlag = true; + } + } + fusionFlag |= !summoned && Bot.HasInHand(CardId.FallenOfAlbaz) && CheckAlbazFusion(); + fusionFlag |= Bot.HasInHandOrInSpellZone(CardId.BrandedInWhite) && BrandedInWhiteActivateCheck(); + fusionFlag |= Bot.HasInHandOrInSpellZone(CardId.BrandedInRed) && BrandedInRedActivateCheck() != null; + + return fusionFlag; + }); + lubellionCheckDict.Add(CardId.BrandedBeast, () => true); + } + else if (hint == HintMsg.AddToHand) + { + lubellionCheckDict.Add(CardId.BystialSaronir, () => true); + } + + foreach (KeyValuePair> pair in lubellionCheckDict) + { + ClientCard target = cards.FirstOrDefault(c => c.Id == pair.Key); + if (target != null && pair.Value()) + { + SelectSTPlace(target, false); + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + break; + + // for albaz + case CardId.FallenOfAlbaz: + case CardId.FallenOfAlbaz + 1: + if (hint == HintMsg.SpSummon) + { + List fusionTargetIdList = new List { + CardId.MirrorjadeTheIcebladeDragon, CardId.AlbaLenatusTheAbyssDragon, CardId.AlbionTheBrandedDragon, CardId.AlbionTheSanctifireDragon, + CardId.LubellionTheSearingDragon, CardId.BorreloadFuriousDragon, CardId.TitanikladTheAshDragon, CardId.RindbrummTheStrikingDragon + }; + foreach (int targetId in fusionTargetIdList) + { + if (targetId == CardId.LubellionTheSearingDragon && Bot.Hand.Count == 0) continue; + ClientCard target = cards.FirstOrDefault(c => c.IsCode(targetId)); + if (target != null) + { + fusionTarget = target; + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + if (hint == HintMsg.FusionMaterial) + { + if (cards.Count == 1) + { + selectedFusionMaterial.AddRange(cards); + return Util.CheckSelectCount(cards, cards, min, max); + } + // select best enemy monster + List sortedResult = cards.OrderByDescending(card => card.GetDefensePower()).ToList(); + selectedFusionMaterial.Add(sortedResult[0]); + return Util.CheckSelectCount(sortedResult, cards, min, max); + } + break; + + // for quem + case CardId.GuidingQuemTheVirtuous: + { + Dictionary> quemCheckDict = new Dictionary> + { + {CardId.BlazingCartesiaTheVirtuous, () => sendToGYThisTurn.Any(c => c.IsCode(CardId.AlbionTheBrandedDragon)) && CheckRemainInDeck(CardId.BrandedInHighSpirits) > 0 }, + {CardId.BrandedFusion, () => Bot.HasInGraveyard(CardId.BrandedRetribution) }, + {CardId.FallenOfAlbaz, () => !Bot.HasInGraveyard(CardId.FallenOfAlbaz) }, + {CardId.TriBrigadeMercourier, () => Bot.HasInHandOrInSpellZone(CardId.BrandedInWhite) }, + {CardId.BrandedRetribution, () => true }, + {CardId.BrightestBlazingBrandedKing, () => !Bot.MonsterZone.Any(c => c != null && c.IsFaceup() && c.IsCode(albazFusionMonster) && fusionToGYFlag) }, + {CardId.BrandedInHighSpirits, () => fusionToGYFlag }, + {CardId.AlbionTheShroudedDragon, () => true }, + }; + + foreach (KeyValuePair> pair in quemCheckDict) + { + ClientCard target = cards.FirstOrDefault(card => card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + break; + + // for cartesia + case CardId.BlazingCartesiaTheVirtuous: + case CardId.BlazingCartesiaTheVirtuous + 1: + if (hint == HintMsg.SpSummon) + { + // fix material list + cartesiaMaterialList = cartesiaMaterialList.Where(c => c != null && (c.Location == CardLocation.MonsterZone || c.Location == CardLocation.Hand)).ToList(); + + // filter normal material + List materialList = Bot.MonsterZone.Where(c => c != null && c.GetDefensePower() <= 2500 && !c.IsCode(cannotBeFusionMaterialIdList)).ToList(); + materialList.AddRange(Bot.Hand.Where(c => c.IsMonster() + && !(CheckWhetherCanSummon() && + ((!activatedCardIdList.Contains(CardId.AluberTheJesterOfDespia) && c.IsCode(CardId.AluberTheJesterOfDespia)) + || (!activatedCardIdList.Contains(CardId.SpringansKitt) && c.IsCode(CardId.SpringansKitt))) + ) + ) + ); + + if (cartesiaSummonGoal > 0) + { + BlazingCartesiaTheVirtuousFusionCheck(cards, cartesiaSummonGoal, materialList, cartesiaMaterialList, out ClientCard _fusionTarget1, out _); + if (_fusionTarget1 != null) + { + fusionTarget = _fusionTarget1; + return Util.CheckSelectCount(new List { fusionTarget }, cards, min, max); + } + } + BlazingCartesiaTheVirtuousFusionCheck(cards, 0, materialList, cartesiaMaterialList, out ClientCard _fusionTarget2, out _); + if (_fusionTarget2 != null) + { + fusionTarget = _fusionTarget2; + return Util.CheckSelectCount(new List { fusionTarget }, cards, min, max); + } + + } + if (hint == HintMsg.FusionMaterial) + { + List mustSelectMaterialList = cartesiaMaterialList.Intersect(cards).ToList(); + if (mustSelectMaterialList != null && mustSelectMaterialList.Count > 0) + { + selectedFusionMaterial.Add(mustSelectMaterialList[0]); + return Util.CheckSelectCount(mustSelectMaterialList, cards, min, max); + } + + ClientCard lubellion = cards.FirstOrDefault(c => c != null && c.IsCode(CardId.TheBystialLubellion) && c.Location == CardLocation.MonsterZone); + if (lubellion != null && !Bot.HasInHandOrInSpellZone(CardId.BrandedBeast)) + { + if (activatedCardIdList.Contains(CardId.TheBystialLubellion + 1) || CheckRemainInDeck(CardId.BrandedLost, CardId.BrandedBeast) == 0) + { + if (Util.IsTurn1OrMain2() || Enemy.MonsterZone.Count(c => c != null && c.GetDefensePower() < 2500) > 0) + { + return Util.CheckSelectCount(new List { lubellion }, cards, min, max); + } + } + } + + ClientCard selectTarget = cards + .Where(c => c.Attack <= 2500 && !(CheckWhetherCanSummon() && + ((!activatedCardIdList.Contains(CardId.AluberTheJesterOfDespia) && c.IsCode(CardId.AluberTheJesterOfDespia)) + || (!activatedCardIdList.Contains(CardId.SpringansKitt) && c.IsCode(CardId.SpringansKitt))) + ) + ) + .OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + if (selectTarget != null) + { + selectedFusionMaterial.Add(selectTarget); + return Util.CheckSelectCount(new List { selectTarget }, cards, min, max); + } + selectTarget = cards.OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + if (selectTarget != null) + { + selectedFusionMaterial.Add(selectTarget); + return Util.CheckSelectCount(new List { selectTarget }, cards, min, max); + } + } + break; + + // for nadir + case CardId.NadirServant: + if (hint == HintMsg.ToGrave) + { + if (summoned) + { + if (CheckRemainInDeck(CardId.BlazingCartesiaTheVirtuous) > 0) + { + ClientCard lulu = cards.FirstOrDefault(c => c.IsOriginalCode(CardId.DespianLuluwalilith)); + if (lulu != null) + { + return Util.CheckSelectCount(new List { lulu }, cards, min, max); + } + } + if (!Bot.MonsterZone.Any(c => c != null && c.HasType(CardType.Fusion)) && CheckRemainInDeck(CardId.SpringansKitt) > 0) + { + ClientCard ironDragon = cards.FirstOrDefault(c => c.IsOriginalCode(CardId.SprindTheIrondashDragon)); + if (ironDragon != null) + { + return Util.CheckSelectCount(new List { ironDragon }, cards, min, max); + } + } + } + NadirServantActivateCheck(cards, true, out ClientCard target); + if (target != null) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + break; + + // for deployment + case CardId.FusionDeployment: + { + int summonId = FusionDeploymentSpSummonTarget(); + if (summonId > 0) + { + if (hint == HintMsg.Confirm) + { + if (summonId == CardId.BlazingCartesiaTheVirtuous) + { + ClientCard target = cards.FirstOrDefault(card => card.IsCode(CardId.GranguignolTheDuskDragon)); + if (target != null) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + else if (summonId == CardId.FallenOfAlbaz) + { + List shuffleList = ShuffleList(new List(cards)); + foreach (ClientCard target in shuffleList) + { + if (target.IsCode(albazFusionMonster)) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + } + if (hint == HintMsg.SpSummon) + { + foreach (ClientCard target in cards) + { + if (target.IsCode(summonId)) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + } + } + break; + + // for branded in white + case CardId.BrandedInWhite: + if (hint == HintMsg.SpSummon) + { + BrandedInWhiteFusionTarget(cards, out ClientCard target); + if (target != null) + { + fusionTarget = target; + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + if (hint == HintMsg.FusionMaterial && fusionTarget != null) + { + if (fusionTarget.IsCode(CardId.BorreloadFuriousDragon)) + { + // select 2 dark dragon monster + foreach (CardLocation loc in new[] { CardLocation.Grave, CardLocation.Hand, CardLocation.MonsterZone }) + { + List cardsInLoc = cards.Where(c => c.Location == loc).OrderBy(c => c.GetDefensePower()).ToList(); + int banishedAlbazCount = Bot.Banished.Where(c => c.IsOriginalCode(CardId.FallenOfAlbaz)).Count(); + banishedAlbazCount += selectedFusionMaterial.Where(c => c.IsOriginalCode(CardId.FallenOfAlbaz)).Count(); + foreach (ClientCard target in cardsInLoc) + { + // keep albaz + if (target.IsOriginalCode(CardId.FallenOfAlbaz) && banishedAlbazCount > 0) + { + continue; + } + selectedFusionMaterial.Add(target); + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + if (fusionTarget.IsCode(CardId.DespianQuaeritis)) + { + // select despain + if (selectedFusionMaterial.Count == 0) + { + foreach (CardLocation loc in new[] { CardLocation.Grave, CardLocation.Hand, CardLocation.MonsterZone }) + { + List cardsInLoc = cards.Where(c => c.Location == loc && c.HasSetcode(SetcodeDespain) && (loc != CardLocation.Grave || !CheckWhetherShouldKeepInGrave(c))) + .OrderBy(c => c.GetDefensePower()).ToList(); + if (cardsInLoc.Count > 0) + { + selectedFusionMaterial.Add(cardsInLoc[0]); + return Util.CheckSelectCount(cardsInLoc, cards, min, max); + } + } + } + // select light/dark + else + { + foreach (CardLocation loc in new[] { CardLocation.Grave, CardLocation.Hand, CardLocation.MonsterZone }) + { + List cardsInLoc = cards.Where(c => c.Location == loc && c.HasAttribute(CardAttribute.Light | CardAttribute.Dark) && (loc != CardLocation.Grave || !CheckWhetherShouldKeepInGrave(c))) + .OrderBy(c => c.GetDefensePower()).ToList(); + if (cardsInLoc.Count > 0) + { + if (!activatedCardIdList.Contains(CardId.TriBrigadeMercourier + 1)) + { + ClientCard mercourier = cardsInLoc.FirstOrDefault(c => c.IsCode(CardId.TriBrigadeMercourier)); + if (mercourier != null) + { + selectedFusionMaterial.Add(mercourier); + return Util.CheckSelectCount(new List { mercourier }, cards, min, max); + } + } + if (!activatedCardIdList.Contains(CardId.DespianTragedy) && CheckRemainInDeck(CardId.AluberTheJesterOfDespia, CardId.GuidingQuemTheVirtuous) > 0) + { + ClientCard tragedy = cardsInLoc.FirstOrDefault(c => c.IsCode(CardId.DespianTragedy)); + if (tragedy != null) + { + selectedFusionMaterial.Add(tragedy); + return Util.CheckSelectCount(new List { tragedy }, cards, min, max); + } + } + + selectedFusionMaterial.Add(cardsInLoc[0]); + return Util.CheckSelectCount(cardsInLoc, cards, min, max); + } + } + } + } + if (fusionTarget.IsCode(CardId.GuardianChimera)) + { + List goalMaterialList = ChimeraFusionMaterialList().Intersect(cards).ToList(); + if (goalMaterialList.Count > 0) + { + return Util.CheckSelectCount(goalMaterialList, cards, min, max); + } + } + if (fusionTarget.IsCode(albazFusionMonster)) + { + // selecting albaz + if (selectedFusionMaterial.Count == 0) + { + foreach (CardLocation loc in new[] { CardLocation.Grave, CardLocation.MonsterZone, CardLocation.Hand }) + { + ClientCard albaz = cards.Where(c => c.IsCode(CardId.FallenOfAlbaz)).OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + if (albaz != null) + { + selectedFusionMaterial.Add(albaz); + return Util.CheckSelectCount(new List { albaz }, cards, min, max); + } + } + } + else + { + if (fusionTarget.IsOriginalCode(CardId.AlbaLenatusTheAbyssDragon) && cancelable) + { + return null; + } + if (Util.IsTurn1OrMain2() && !CheckWhetherWillbeRemoved()) + { + ClientCard duskDragon = cards.FirstOrDefault(c => c.IsCode(CardId.GranguignolTheDuskDragon) && c.Location == CardLocation.MonsterZone); + if (duskDragon != null) + { + selectedFusionMaterial.Add(duskDragon); + return Util.CheckSelectCount(new List { duskDragon }, cards, min, max); + } + } + List> funcList = new List> + { + (c) => c.Location == CardLocation.Grave && !CheckWhetherShouldKeepInGrave(c), + (c) => c.Location == CardLocation.MonsterZone && c.GetDefensePower() <= 2000, + (c) => c.Location == CardLocation.Hand, + (c) => c.Location == CardLocation.Grave, + (c) => c.Location == CardLocation.MonsterZone + }; + foreach (Func func in funcList) + { + List targetList = cards.Where(c => func(c)).OrderBy(c => c.GetDefensePower()).ToList(); + if (targetList.Count > 0) + { + selectedFusionMaterial.Add(targetList[0]); + return Util.CheckSelectCount(new List { targetList[0] }, cards, min, max); + } + } + } + } + } + break; + + // for branded fusion + case CardId.BrandedFusion: + if (hint == HintMsg.SpSummon) + { + Dictionary> brandedFusionCheckDict = new Dictionary> + { + {CardId.TitanikladTheAshDragon, () => Enemy.HasInMonstersZone(CardId.KashtiraAriseHeart) }, + {CardId.RindbrummTheStrikingDragon, () => CheckWhetherWillbeRemoved() && CheckRemainInDeck(CardId.TriBrigadeMercourier) > 0}, + {CardId.AlbionTheSanctifireDragon, () => CheckShouldNoMoreSpSummon()}, + {CardId.AlbionTheBrandedDragon, () => { + bool checkFlag = Bot.Graveyard.Any(c => c != null && c.IsMonster() && c.HasAttribute(CardAttribute.Dark) && !c.IsCode(cannotBeFusionMaterialIdList)); + checkFlag |= Bot.HasInHandOrHasInMonstersZone(CardId.TriBrigadeMercourier); + checkFlag |= Bot.GetMonsters().Any(c => c.GetDefensePower() <= 1800 && c.HasAttribute(CardAttribute.Dark) && !c.IsCode(cannotBeFusionMaterialIdList)); + return checkFlag; + } }, + {CardId.LubellionTheSearingDragon, () => !CheckWhetherNegated(true, true, CardType.Monster) && Bot.Hand.Count > 0 }, + {CardId.MirrorjadeTheIcebladeDragon, () => Bot.HasInMonstersZone(new List{ + CardId.GranguignolTheDuskDragon, CardId.AlbionTheBrandedDragon, CardId.LubellionTheSearingDragon}) } + }; + + foreach (KeyValuePair> pair in brandedFusionCheckDict) + { + ClientCard target = cards.FirstOrDefault(card => card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + fusionTarget = target; + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + if (hint == HintMsg.FusionMaterial) + { + // selecting albaz + if (selectedFusionMaterial.Count == 0) + { + foreach (CardLocation loc in new[] { CardLocation.Deck, CardLocation.Hand, CardLocation.MonsterZone }) + { + ClientCard target = cards.FirstOrDefault(c => c.IsOriginalCode(CardId.FallenOfAlbaz) && c.Location == loc); + if (target != null) + { + selectedFusionMaterial.Add(target); + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + // selecting another material + if (fusionTarget != null) + { + Dictionary> materialDict = new Dictionary> + { + { CardId.AlbionTheSanctifireDragon, new List{CardId.BlazingCartesiaTheVirtuous, _CardId.EffectVeiler, CardId.GuidingQuemTheVirtuous} }, + { CardId.MirrorjadeTheIcebladeDragon, new List{CardId.GranguignolTheDuskDragon, CardId.AlbionTheBrandedDragon, CardId.DespianLuluwalilith } }, + { CardId.LubellionTheSearingDragon, new List{ + CardId.DespianTragedy, CardId.BystialSaronir, CardId.AlbionTheShroudedDragon, CardId.AluberTheJesterOfDespia, CardId.TriBrigadeMercourier } }, + { CardId.TitanikladTheAshDragon, new List{CardId.TheBystialLubellion, CardId.AlbionTheShroudedDragon, CardId.BystialSaronir} }, + { CardId.RindbrummTheStrikingDragon, new List{CardId.TriBrigadeMercourier, CardId.SpringansKitt } }, + { CardId.AlbionTheBrandedDragon, new List{CardId.TheBystialLubellion, CardId.BlazingCartesiaTheVirtuous, CardId.GuidingQuemTheVirtuous } } + }; + materialDict.TryGetValue(fusionTarget.GetOriginCode(), out List checkIdList); + if (checkIdList != null && checkIdList.Count > 0) + { + foreach (CardLocation location in new List { CardLocation.Deck, CardLocation.Hand, CardLocation.MonsterZone }) + { + foreach (int checkId in checkIdList) + { + ClientCard target = cards.FirstOrDefault(c => c.Location == location && c.IsCode(checkId)); + if (target != null) + { + selectedFusionMaterial.Add(target); + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + } + } + } + break; + + // for Sarcophagus + case CardId.GoldSarcophagus: + { + GoldSarcophagusTarget(cards, out ClientCard sarcophagusTarget); + if (sarcophagusTarget != null) + { + return Util.CheckSelectCount(new List { sarcophagusTarget }, cards, min, max); + } + } + break; + + // for burial + case CardId.FoolishBurial: + case CardId.FoolishBurial + 1: + { + FoolishBurialTarget(cards, out ClientCard burialTarget); + if (burialTarget != null) + { + return Util.CheckSelectCount(new List { burialTarget }, cards, min, max); + } + } + break; + + // for high spirit + case CardId.BrandedInHighSpirits: + // confirm + if (hint == HintMsg.Confirm) + { + if (Duel.Phase == DuelPhase.End && Bot.HasInMonstersZone(CardId.GuidingQuemTheVirtuous)) + { + ClientCard cartesia = cards.FirstOrDefault(c => c.IsOriginalCode(CardId.BlazingCartesiaTheVirtuous)); + if (cartesia != null) + { + fusionTarget = cartesia; + return Util.CheckSelectCount(new List { cartesia }, cards, min, max); + } + } + bool activatingShroudedFlag = Duel.CurrentChain.Any(c => c.IsOriginalCode(CardId.AlbionTheShroudedDragon) && c.Location == CardLocation.Hand); + if (activatingShroudedFlag) + { + ClientCard shrouded = cards.FirstOrDefault(c => c.IsOriginalCode(CardId.AlbionTheShroudedDragon)); + if (shrouded != null) + { + fusionTarget = shrouded; + return Util.CheckSelectCount(new List { shrouded }, cards, min, max); + } + } + List discardIdList = new List { + CardId.BystialSaronir, CardId.AlbionTheShroudedDragon, CardId.TheBystialLubellion, CardId.BlazingCartesiaTheVirtuous, + CardId.FallenOfAlbaz, CardId.TriBrigadeMercourier + }; + foreach (int discardId in discardIdList) + { + ClientCard target = cards.FirstOrDefault(c => c.IsOriginalCode(discardId)); + if (target != null) + { + // lubellion check + if (discardId == CardId.TheBystialLubellion && Duel.Player == 0 && (Duel.Phase <= DuelPhase.Main1 || Duel.Phase == DuelPhase.Main2) + && CheckRemainInDeck(CardId.BystialSaronir) > 0 && !activatedCardIdList.Contains(CardId.TheBystialLubellion)) + { + continue; + } + fusionTarget = target; + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + // discard + if (hint == HintMsg.ToGrave) + { + List discardIdList = new List { + CardId.AlbionTheBrandedDragon, CardId.TitanikladTheAshDragon, CardId.RindbrummTheStrikingDragon, CardId.AlbaLenatusTheAbyssDragon, + CardId.GranguignolTheDuskDragon + }; + foreach (int discardId in discardIdList) + { + if (sendToGYThisTurn.Any(c => c.IsOriginalCode(discardId))) continue; + ClientCard target = cards.FirstOrDefault(c => c.IsOriginalCode(discardId)); + if (target != null) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + break; + + // for opening + case CardId.BrandedOpening: + if (hint == HintMsg.OperateCard) + { + Dictionary> openingCheckDict = new Dictionary>{ + {CardId.AluberTheJesterOfDespia, () => !activatedCardIdList.Contains(CardId.AluberTheJesterOfDespia) && !DefaultCheckWhetherCardIdIsNegated(CardId.AluberTheJesterOfDespia) + && !(CheckWhetherCanSummon() && Bot.HasInHand(CardId.AluberTheJesterOfDespia))}, + {CardId.GuidingQuemTheVirtuous, () => true }, + {CardId.DespianTragedy, () => true } + }; + foreach (KeyValuePair> pair in openingCheckDict) + { + ClientCard target = cards.FirstOrDefault(card => card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + break; + + // for branded in red + case CardId.BrandedInRed: + if (hint == HintMsg.SpSummon) + { + // filter normal material + List materialList = Bot.MonsterZone.Where(c => c != null && c.GetDefensePower() <= 2500 && !c.IsCode(cannotBeFusionMaterialIdList)).ToList(); + materialList.AddRange(Bot.Hand.Where(c => c.IsMonster() + && !(CheckWhetherCanSummon() && + ((!activatedCardIdList.Contains(CardId.AluberTheJesterOfDespia) && c.IsCode(CardId.AluberTheJesterOfDespia)) + || (!activatedCardIdList.Contains(CardId.SpringansKitt) && c.IsCode(CardId.SpringansKitt))) + ) + ) + ); + + BrandedInRedFusionCheck(cards, 0, materialList, brandedInRedMaterialList, out ClientCard _fusionTarget, out _); + if (_fusionTarget != null) + { + fusionTarget = _fusionTarget; + return Util.CheckSelectCount(new List { fusionTarget }, cards, min, max); + } + + } + if (hint == HintMsg.FusionMaterial) + { + List mustSelectMaterialList = brandedInRedMaterialList.Intersect(cards).ToList(); + if (mustSelectMaterialList != null && mustSelectMaterialList.Count > 0) + { + selectedFusionMaterial.Add(mustSelectMaterialList[0]); + return Util.CheckSelectCount(mustSelectMaterialList, cards, min, max); + } + + ClientCard selectTarget = cards + .Where(c => c.Attack <= 2500 && !(CheckWhetherCanSummon() && + ((!activatedCardIdList.Contains(CardId.AluberTheJesterOfDespia) && c.IsCode(CardId.AluberTheJesterOfDespia)) + || (!activatedCardIdList.Contains(CardId.SpringansKitt) && c.IsCode(CardId.SpringansKitt))) + ) + ) + .OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + if (selectTarget != null) + { + selectedFusionMaterial.Add(selectTarget); + return Util.CheckSelectCount(new List { selectTarget }, cards, min, max); + } + selectTarget = cards.OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + if (selectTarget != null) + { + selectedFusionMaterial.Add(selectTarget); + return Util.CheckSelectCount(new List { selectTarget }, cards, min, max); + } + } + break; + + // for branded king + case CardId.BrightestBlazingBrandedKing: + if (hint == HintMsg.Faceup) + { + List targetIdList = new List + { + CardId.MirrorjadeTheIcebladeDragon, CardId.AlbionTheSanctifireDragon, CardId.RindbrummTheStrikingDragon + }; + List> funcList = new List> + { + (c) => Duel.CurrentChain.Contains(c), + (c) => true + }; + foreach (Func func in funcList) + { + List chainedList = cards.Where(c => func(c)).ToList(); + if (chainedList.Count > 0) + { + foreach (int checkId in targetIdList) + { + ClientCard target = chainedList.FirstOrDefault(c => c.IsOriginalCode(checkId)); + if (target != null) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + ClientCard otherChainTarget = chainedList.FirstOrDefault(c => Duel.CurrentChain.Contains(c)); + if (otherChainTarget != null) + { + return Util.CheckSelectCount(new List { otherChainTarget }, cards, min, max); + } + } + } + } + break; + + // for retribution + case CardId.BrandedRetribution: + { + ClientCard searing = cards.FirstOrDefault(c => c.IsCode(CardId.LubellionTheSearingDragon)); + if (searing != null) + { + selectedFusionMaterial.Add(searing); + return Util.CheckSelectCount(new List { searing }, cards, min, max); + } + List checkIdList = new List { CardId.AlbionTheBrandedDragon, CardId.MirrorjadeTheIcebladeDragon, CardId.TitanikladTheAshDragon, CardId.AlbaLenatusTheAbyssDragon, + CardId.AlbionTheSanctifireDragon, CardId.SprindTheIrondashDragon}; + foreach (int checkId in checkIdList) + { + List gravePriorityList = cards.Where(c => c != null && c.IsCode(checkId) && c.Location == CardLocation.Grave && !CheckWhetherShouldKeepInGrave(c)).ToList(); + if (gravePriorityList.Count > 0) + { + selectedFusionMaterial.Add(gravePriorityList[0]); + return Util.CheckSelectCount(new List { gravePriorityList[0] }, cards, min, max); + } + } + List graveList = cards.Where(c => c != null && c.Location == CardLocation.Grave).ToList(); + if (graveList.Count > 0) + { + selectedFusionMaterial.Add(graveList[0]); + return Util.CheckSelectCount(new List { graveList[0] }, cards, min, max); + } + ClientCard monsterOnField = cards.Where(c => c != null && c.Location == CardLocation.MonsterZone).OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + if (monsterOnField != null) + { + selectedFusionMaterial.Add(monsterOnField); + return Util.CheckSelectCount(new List { monsterOnField }, cards, min, max); + } + } + break; + + // for chimera + case CardId.GuardianChimera: + { + List targetList = new List(); + + targetList.AddRange(GetProblematicEnemyCardList(false, false, CardType.Monster)); + int bestBotPower = Util.GetBestPower(Bot); + targetList.AddRange(Enemy.MonsterZone.Where(c => c != null && !targetList.Contains(c) && c.GetDefensePower() >= bestBotPower).OrderByDescending(c => c.GetDefensePower())); + targetList.AddRange(ShuffleList(enemyPlaceThisTurn)); + + return Util.CheckSelectCount(targetList, cards, min, max); + } + break; + + // for sanctifire + case CardId.AlbionTheSanctifireDragon: + if (hint == Util.GetStringId(CardId.AlbionTheSanctifireDragon, 1)) + { + ClientCard albaz = cards.FirstOrDefault(c => c.IsOriginalCode(CardId.FallenOfAlbaz)); + if (albaz != null && CheckAlbazFusion()) + { + return Util.CheckSelectCount(new List { albaz }, cards, min, max); + } + + ClientCard floogate = cards.Where(c => c.IsFloodgate()).OrderByDescending(c => c.GetDefensePower()).FirstOrDefault(); + if (floogate != null) + { + return Util.CheckSelectCount(new List { floogate }, cards, min, max); + } + + return Util.CheckSelectCount(cards.OrderByDescending(c => c.GetDefensePower()).ToList(), cards, min, max); + } + break; + + // for mirrorjade + case CardId.MirrorjadeTheIcebladeDragon: + { + List floodgateList = ShuffleList(cards.Where(c => c.Controller == 1 && c.IsFloodgate()).ToList()); + if (floodgateList.Count > 0) + { + return Util.CheckSelectCount(floodgateList, cards, min, max); + } + + List extraMonsterList = cards.Where(c => c.Controller == 1 && ( + c.HasType(CardType.Fusion | CardType.Ritual | CardType.Synchro | CardType.Xyz) + || (c.HasType(CardType.Link) && c.LinkCount >= 2))).OrderByDescending(c => c.GetDefensePower()).ToList(); + if (extraMonsterList.Count > 0) + { + return Util.CheckSelectCount(extraMonsterList, cards, min, max); + } + + ClientCard worstBotMonster = Util.GetWorstBotMonster(); + int worstBotPower = worstBotMonster == null ? 0 : worstBotMonster.GetDefensePower(); + List betterMonsterList = cards.Where(c => c.Controller == 1 && c.GetDefensePower() >= worstBotPower).OrderByDescending(c => c.GetDefensePower()).ToList(); + if (betterMonsterList.Count > 0) + { + return Util.CheckSelectCount(betterMonsterList, cards, min, max); + } + + List dangerMonsterList = cards.Where(c => c.Controller == 1 && (c.IsMonsterDangerous() || c.IsMonsterInvincible())) + .OrderByDescending(c => c.GetDefensePower()).ToList(); + if (dangerMonsterList.Count > 0) + { + return Util.CheckSelectCount(dangerMonsterList, cards, min, max); + } + + List allEnemyMonsterList = cards.Where(c => c.Controller == 1).OrderByDescending(c => c.IsFacedown() ? 0 : c.GetDefensePower()).ToList(); + if (allEnemyMonsterList.Count > 0) + { + return Util.CheckSelectCount(allEnemyMonsterList, cards, min, max); + } + + ClientCard botMonsterWithEffect = cards.FirstOrDefault(c => c.Controller == 0 && c.IsCode(new[] { CardId.DespianTragedy, CardId.TriBrigadeMercourier })); + if (botMonsterWithEffect != null) + { + return Util.CheckSelectCount(new List { botMonsterWithEffect }, cards, min, max); + } + ClientCard botLubellion = cards.FirstOrDefault(c => c.Controller == 0 && c.IsCode(CardId.TheBystialLubellion)); + if (botLubellion != null) + { + return Util.CheckSelectCount(new List { botLubellion }, cards, min, max); + } + + + List allBotMonster = cards.Where(c => c.Controller == 0).OrderBy(c => c.IsFacedown() ? 0 : c.GetDefensePower()).ToList(); + if (allBotMonster.Count > 0) + { + return Util.CheckSelectCount(allBotMonster, cards, min, max); + } + } + break; + + // for searing dragon + case CardId.LubellionTheSearingDragon: + if (hint == HintMsg.SpSummon) + { + LubellionTheSearingDragonFusionTarget(cards, out ClientCard target); + if (target != null) + { + fusionTarget = target; + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + if (hint == HintMsg.FusionMaterial && fusionTarget != null) + { + if (fusionTarget.IsCode(CardId.BorreloadFuriousDragon)) + { + // select 2 dark dragon monster + List> furiousFuncList = new List> + { + (c) => c.IsFaceup() && c.Location == CardLocation.Removed && c.IsCode(CardId.AlbionTheBrandedDragon), + (c) => c.IsFaceup() && c.Location == CardLocation.Removed && c.IsCode(CardId.FallenOfAlbaz), + (c) => c.Location == CardLocation.Grave && c.IsCode(CardId.AlbionTheBrandedDragon) && !CheckWhetherShouldKeepInGrave(c), + (c) => c.IsFaceup() && c.Location == CardLocation.Removed && c.IsCode(CardId.TitanikladTheAshDragon), + (c) => c.IsFaceup() && c.Location == CardLocation.Removed, + (c) => c.Location == CardLocation.Grave && !CheckWhetherShouldKeepInGrave(c), + (c) => c.Location == CardLocation.Grave, + (c) => c.Location == CardLocation.Hand || c.Location == CardLocation.MonsterZone + }; + + foreach (Func func in furiousFuncList) + { + List cardWithFunc = cards.Where(c => func(c)).OrderBy(c => c.GetDefensePower()).ToList(); + if (cardWithFunc.Count > 0) + { + selectedFusionMaterial.Add(cardWithFunc[0]); + return Util.CheckSelectCount(new List { cardWithFunc[0] }, cards, min, max); + } + } + } + List> funcList = new List> + { + (c) => c.IsFaceup() && c.Location == CardLocation.Removed, + (c) => c.Location == CardLocation.Grave && !CheckWhetherShouldKeepInGrave(c), + (c) => c.IsCode(CardId.LubellionTheSearingDragon), + (c) => c.Location == CardLocation.Grave, + (c) => c.Location == CardLocation.MonsterZone, + (c) => c.Location == CardLocation.Hand, + }; + if (selectedFusionMaterial.Count == 0) + { + if (fusionTarget.IsOriginalCode(CardId.DespianQuaeritis)) + { + foreach (Func func in funcList) + { + List cardsWithFunc = cards.Where(c => func(c) && c.HasSetcode(SetcodeDespain)).OrderBy(c => c.GetDefensePower()).ToList(); + if (cardsWithFunc.Count > 0) + { + selectedFusionMaterial.Add(cardsWithFunc[0]); + return Util.CheckSelectCount(cardsWithFunc, cards, min, max); + } + } + } + if (fusionTarget.IsCode(albazFusionMonster)) + { + foreach (Func func in funcList) + { + List cardsWithFunc = cards.Where(c => func(c) && c.IsCode(CardId.FallenOfAlbaz)).OrderBy(c => c.GetDefensePower()).ToList(); + if (cardsWithFunc.Count > 0) + { + selectedFusionMaterial.Add(cardsWithFunc[0]); + return Util.CheckSelectCount(cardsWithFunc, cards, min, max); + } + } + } + } + if (fusionTarget.IsCode(CardId.AlbaLenatusTheAbyssDragon)) + { + // select non-albaz + if (selectedFusionMaterial.Count > 0) + { + funcList = new List> + { + (c) => c.IsFaceup() && c.Location == CardLocation.Removed, + (c) => c.Location == CardLocation.Grave && !CheckWhetherShouldKeepInGrave(c), + (c) => c.IsCode(CardId.LubellionTheSearingDragon), + }; + } + } + foreach (Func func in funcList) + { + List cardsWithFunc = cards.Where(c => func(c)).OrderBy(c => c.GetDefensePower()).ToList(); + if (cardsWithFunc.Count > 0) + { + selectedFusionMaterial.Add(cardsWithFunc[0]); + return Util.CheckSelectCount(cardsWithFunc, cards, min, max); + } + } + if (fusionTarget.IsOriginalCode(CardId.AlbaLenatusTheAbyssDragon) && cancelable) + { + return null; + } + } + break; + + // for granguignol + case CardId.GranguignolTheDuskDragon: + if (hint == HintMsg.ToGrave) + { + GranguignolTheDuskDragonSendToGYTarget(cards, out ClientCard target); + if (target != null) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + if (hint == HintMsg.SpSummon) + { + Dictionary> checkDict = new Dictionary> + { + {CardId.DespianQuaeritis, () => Enemy.MonsterZone.Any(c => c != null && c.IsFaceup() && c.Attack >= Util.GetBestPower(Bot) && !(c.HasType(CardType.Fusion) && c.Level >= 8)) }, + {CardId.GuidingQuemTheVirtuous, () => Bot.HasInMonstersZone(CardId.MirrorjadeTheIcebladeDragon) || Util.GetOneEnemyBetterThanValue(1500) == null }, + {CardId.DespianLuluwalilith, () => !(Duel.Player == 0 && Bot.HasInHandOrInSpellZone(CardId.BrandedFusion)) } + }; + + foreach (KeyValuePair> pair in checkDict) + { + ClientCard target = cards.FirstOrDefault(c => c.IsOriginalCode(pair.Key)); + if (target != null && pair.Value()) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + break; + + // for Quaeritis + case CardId.DespianQuaeritis: + { + Dictionary> checkDict = new Dictionary> + { + {CardId.FallenOfAlbaz, () => CheckAlbazFusion() }, + {CardId.GuidingQuemTheVirtuous, () => !DefaultCheckWhetherCardIdIsNegated(CardId.GuidingQuemTheVirtuous) }, + {CardId.AluberTheJesterOfDespia, () => !DefaultCheckWhetherCardIdIsNegated(CardId.AluberTheJesterOfDespia) }, + {CardId.DespianTragedy, () => true } + }; + + foreach (KeyValuePair> pair in checkDict) + { + ClientCard target = cards.FirstOrDefault(card => card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + fusionTarget = target; + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + break; + + // for irondash dragon + case CardId.SprindTheIrondashDragon: + { + Dictionary> checkDict = new Dictionary> + { + {CardId.FallenOfAlbaz, () => CheckAlbazFusion() }, + {CardId.SpringansKitt, () => !DefaultCheckWhetherCardIdIsNegated(CardId.SpringansKitt) } + }; + + foreach (KeyValuePair> pair in checkDict) + { + ClientCard target = cards.FirstOrDefault(card => card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + fusionTarget = target; + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + break; + + // for ash dragon + case CardId.TitanikladTheAshDragon: + { + Dictionary> checkDict = new Dictionary> + { + {CardId.FallenOfAlbaz, () => CheckAlbazFusion() }, + {CardId.GuidingQuemTheVirtuous, () => !DefaultCheckWhetherCardIdIsNegated(CardId.GuidingQuemTheVirtuous) } + }; + + foreach (KeyValuePair> pair in checkDict) + { + ClientCard target = cards.FirstOrDefault(card => card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + fusionTarget = target; + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + break; + + // for rindrumm + case CardId.RindbrummTheStrikingDragon: + if (hint == HintMsg.SpSummon) + { + Dictionary> checkDict = new Dictionary> + { + {CardId.FallenOfAlbaz, () => CheckAlbazFusion() }, + {CardId.RindbrummTheStrikingDragon, () => true }, + {CardId.AlbionTheShroudedDragon, () => true } + }; + foreach (KeyValuePair> pair in checkDict) + { + ClientCard target = cards.FirstOrDefault(c => c.IsOriginalCode(pair.Key)); + if (target != null && pair.Value()) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + if (hint == HintMsg.ReturnToHand) + { + List problemList = GetProblematicEnemyCardList(false, true, CardType.Monster).Intersect(cards).OrderByDescending(c => c.GetDefensePower()).ToList(); + if (problemList.Count > 0) + { + return Util.CheckSelectCount(problemList, cards, min, max); + } + ClientCard worstBotMonster = Util.GetWorstBotMonster(); + int worstBotPower = worstBotMonster == null ? 0 : worstBotMonster.GetDefensePower(); + List dangerList = cards.Where(c => c.IsFaceup() && c.Controller == 1 && c.GetDefensePower() > worstBotPower).OrderByDescending(c => c.GetDefensePower()).ToList(); + if (dangerList.Count > 0) + { + return Util.CheckSelectCount(dangerList, cards, min, max); + } + List checkIdList = new List { CardId.AluberTheJesterOfDespia, CardId.SpringansKitt }; + foreach (int checkId in checkIdList) + { + ClientCard target = cards.FirstOrDefault(c => c.Controller == 0 && c.IsCode(checkId)); + if (target != null) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + List enemyMonsterList = cards.Where(c => c.Controller == 1).OrderByDescending(c => c.GetDefensePower()).ToList(); + if (enemyMonsterList.Count > 0) + { + return Util.CheckSelectCount(enemyMonsterList, cards, min, max); + } + return Util.CheckSelectCount(cards.Where(c => c.Controller == 0).OrderByDescending(c => c.GetDefensePower()).ToList(), cards, min, max); + } + break; + + // for branded dragon + case CardId.AlbionTheBrandedDragon: + if (hint == HintMsg.SpSummon) + { + AlbionTheBrandedDragonFusionTarget(cards, out ClientCard target); + if (target != null) + { + fusionTarget = target; + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + if (hint == HintMsg.FusionMaterial && fusionTarget != null) + { + if (fusionTarget.IsCode(CardId.BorreloadFuriousDragon)) + { + // select 2 dark dragon monster + foreach (CardLocation loc in new[] { CardLocation.Grave, CardLocation.Hand, CardLocation.MonsterZone }) + { + List cardsInLoc = cards.Where(c => c.Location == loc).OrderBy(c => c.GetDefensePower()).ToList(); + int banishedAlbazCount = Bot.Banished.Where(c => c.IsOriginalCode(CardId.FallenOfAlbaz)).Count(); + banishedAlbazCount += selectedFusionMaterial.Where(c => c.IsOriginalCode(CardId.FallenOfAlbaz)).Count(); + foreach (ClientCard target in cardsInLoc) + { + // keep albaz + if (target.IsOriginalCode(CardId.FallenOfAlbaz) && banishedAlbazCount > 0) + { + continue; + } + selectedFusionMaterial.Add(target); + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + if (fusionTarget.IsCode(CardId.DespianQuaeritis)) + { + // select despain + if (selectedFusionMaterial.Count == 0) + { + foreach (CardLocation loc in new[] { CardLocation.Grave, CardLocation.Hand, CardLocation.MonsterZone }) + { + List cardsInLoc = cards.Where(c => c.Location == loc && c.HasSetcode(SetcodeDespain) && (loc != CardLocation.Grave || !CheckWhetherShouldKeepInGrave(c))) + .OrderBy(c => c.GetDefensePower()).ToList(); + if (cardsInLoc.Count > 0) + { + selectedFusionMaterial.Add(cardsInLoc[0]); + return Util.CheckSelectCount(cardsInLoc, cards, min, max); + } + } + } + // select light/dark + else + { + foreach (CardLocation loc in new[] { CardLocation.Grave, CardLocation.Hand, CardLocation.MonsterZone }) + { + List cardsInLoc = cards.Where(c => c.Location == loc && c.HasAttribute(CardAttribute.Light | CardAttribute.Dark) && (loc != CardLocation.Grave || !CheckWhetherShouldKeepInGrave(c))) + .OrderBy(c => c.GetDefensePower()).ToList(); + if (cardsInLoc.Count > 0) + { + if (!activatedCardIdList.Contains(CardId.TriBrigadeMercourier + 1)) + { + ClientCard mercourier = cardsInLoc.FirstOrDefault(c => c.IsCode(CardId.TriBrigadeMercourier)); + if (mercourier != null) + { + selectedFusionMaterial.Add(mercourier); + return Util.CheckSelectCount(new List { mercourier }, cards, min, max); + } + } + if (!activatedCardIdList.Contains(CardId.DespianTragedy) && CheckRemainInDeck(CardId.AluberTheJesterOfDespia, CardId.GuidingQuemTheVirtuous) > 0) + { + ClientCard tragedy = cardsInLoc.FirstOrDefault(c => c.IsCode(CardId.DespianTragedy)); + if (tragedy != null) + { + selectedFusionMaterial.Add(tragedy); + return Util.CheckSelectCount(new List { tragedy }, cards, min, max); + } + } + + selectedFusionMaterial.Add(cardsInLoc[0]); + return Util.CheckSelectCount(cardsInLoc, cards, min, max); + } + } + } + } + if (fusionTarget.IsCode(albazFusionMonster)) + { + // selecting albaz + if (selectedFusionMaterial.Count == 0) + { + foreach (CardLocation loc in new[] { CardLocation.Grave, CardLocation.MonsterZone, CardLocation.Hand }) + { + ClientCard albaz = cards.Where(c => c.IsCode(CardId.FallenOfAlbaz) && c.Location == loc).OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + if (albaz != null) + { + selectedFusionMaterial.Add(albaz); + return Util.CheckSelectCount(new List { albaz }, cards, min, max); + } + } + } + else + { + if (fusionTarget.IsOriginalCode(CardId.AlbaLenatusTheAbyssDragon) && cancelable) + { + return null; + } + List> funcList = new List> + { + (c) => c.Location == CardLocation.Grave && !CheckWhetherShouldKeepInGrave(c), + (c) => c.Location == CardLocation.MonsterZone && c.GetDefensePower() <= 2000, + (c) => c.Location == CardLocation.Grave, + (c) => c.Location == CardLocation.Hand, + (c) => c.Location == CardLocation.MonsterZone + }; + foreach (Func func in funcList) + { + List targetList = cards.Where(c => func(c)).OrderBy(c => c.GetDefensePower()).ToList(); + if (targetList.Count > 0) + { + selectedFusionMaterial.Add(targetList[0]); + return Util.CheckSelectCount(new List { targetList[0] }, cards, min, max); + } + } + } + } + } + if (hint == HintMsg.OperateCard) + { + Dictionary> checkDict = new Dictionary> + { + {CardId.BrandedInHighSpirits, () => Bot.HasInMonstersZone(CardId.GuidingQuemTheVirtuous) && BrandedInHighSpiritsActivateCheck() }, + {CardId.BrightestBlazingBrandedKing, () => Bot.MonsterZone.Any(c => c != null && c.IsFaceup() && c.IsCode(albazFusionMonster)) }, + {CardId.BrandedInRed, () => Bot.Graveyard.Any(c => c != null && (c.HasSetcode(SetcodeDespain) || c.IsCode(CardId.FallenOfAlbaz))) }, + {CardId.BrandedRetribution, () => Bot.Graveyard.Where(c => c != null && c.IsCode(albazFusionMonster)).Count() > 1 }, + {CardId.BrandedFusion, () => CheckRemainInDeck(CardId.FallenOfAlbaz) > 0 }, + {CardId.BrandedBeast, () => Bot.MonsterZone.Any(c => c != null && c.IsFaceup() && c.HasSetcode(SetcodeBystial)) }, + {CardId.BrandedLost, () => true }, + {CardId.BrandedInWhite, () => true } + }; + + foreach (KeyValuePair> pair in checkDict) + { + ClientCard target = cards.FirstOrDefault(c => c.IsOriginalCode(pair.Key)); + if (target != null && pair.Value()) + { + fusionTarget = target; + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + break; + + // for luluwa + case CardId.DespianLuluwalilith: + if (hint == HintMsg.Disable) + { + List enemyCardList = cards.Where(c => c.IsFaceup() && c.Controller == 1).ToList(); + List problemCardList = GetProblematicEnemyCardList(false, false, 0).Intersect(enemyCardList).ToList(); + if (problemCardList.Count > 0) + { + return Util.CheckSelectCount(ShuffleList(problemCardList), cards, min, max); + } + List monsterList = GetMonsterListForTargetNegate(false, 0).Intersect(enemyCardList).ToList(); + if (monsterList.Count > 0) + { + return Util.CheckSelectCount(ShuffleList(monsterList), cards, min, max); + } + if (enemyCardList.Count > 0) + { + return Util.CheckSelectCount(ShuffleList(enemyCardList), cards, min, max); + } + } + if (hint == HintMsg.SpSummon) + { + foreach (CardLocation loc in new[] { CardLocation.Deck, CardLocation.Hand }) + { + foreach (int checkId in new List { CardId.BlazingCartesiaTheVirtuous, CardId.GuidingQuemTheVirtuous }) + { + ClientCard target = cards.FirstOrDefault(c => c.Location == loc && c.IsOriginalCode(checkId)); + if (target != null) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + } + break; + + default: + break; + } + } + + // drop 1 hand + bool discardHand = hint == HintMsg.Discard; + bool handToDeck = hint == HintMsg.ToDeck && cards.All(c => c.Location == CardLocation.Hand); + if (min == 1 && max == 1 && (discardHand || handToDeck)) + { + if (currentSolvingChain != null && currentSolvingChain.IsCode(CardId.BrandedOpening)) + { + ClientCard tragedy = cards.FirstOrDefault(card => card.IsCode(CardId.DespianTragedy)); + if (tragedy != null) + { + return Util.CheckSelectCount(new List { tragedy }, cards, min, max); + } + } + if (discardHand) + { + // discard activating shrouded + foreach (ClientCard target in cards) + { + if (target.IsCode(CardId.AlbionTheShroudedDragon) && Duel.CurrentChain.Contains(target)) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + + List discardList = new List { + CardId.BrandedRetribution, CardId.AlbionTheShroudedDragon, CardId.BystialSaronir, CardId.BrightestBlazingBrandedKing, + CardId.BrandedInHighSpirits, CardId.BlazingCartesiaTheVirtuous, CardId.DespianTragedy }; + foreach (int id in discardList) + { + ClientCard card = cards.FirstOrDefault(c => c.IsCode(id)); + if (card != null) + { + return Util.CheckSelectCount(new List { card }, cards, min, max); + } + } + } + // return dump card + foreach (ClientCard card in cards) + { + if (cards.Where(c => c.IsCode(card.Id)).Count() > 1) + { + return Util.CheckSelectCount(new List { card }, cards, min, max); + } + } + List improperCardIdList = new List + { + CardId.BrandedRetribution, CardId.BrandedInHighSpirits, CardId.DespianTragedy, CardId.FusionDeployment, CardId.BrandedBeast, + CardId.AlbionTheShroudedDragon, CardId.BrandedOpening, CardId.GoldSarcophagus, CardId.FoolishBurial, CardId.FallenOfAlbaz, + CardId.BrandedInRed, _CardId.InfiniteImpermanence, CardId.TheBystialLubellion, CardId.BrandedLost, CardId.SpringansKitt, + CardId.GuidingQuemTheVirtuous, _CardId.CrossoutDesignator, _CardId.CalledByTheGrave, CardId.TriBrigadeMercourier, _CardId.AshBlossom, _CardId.MaxxC + }; + foreach (int id in improperCardIdList) + { + if (id == CardId.BrandedLost && Bot.HasInHand(CardId.BrandedFusion) && BrandedFusionActivateCheck()) continue; + ClientCard target = cards.FirstOrDefault(c => c.IsCode(id)); + if (target != null) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + else if (discardHand && min > 0 && min == max) + { + List discardList = new List(); + List graveEffectIdList = new List { CardId.AlbionTheShroudedDragon, CardId.BrandedRetribution, CardId.BrandedInHighSpirits, + CardId.BrightestBlazingBrandedKing, CardId.DespianTragedy }; + discardList.AddRange(ShuffleList(cards.Where(c => c.IsCode(graveEffectIdList)).ToList())); + List remainHandList = cards.Except(discardList).ToList(); + + HashSet seenIds = new HashSet(); + for (int idx = remainHandList.Count - 1; idx >= 0; idx --) + { + ClientCard currentCard = remainHandList[idx]; + if (!seenIds.Add(currentCard.Id)) + { + discardList.Add(currentCard); + remainHandList.Remove(currentCard); + } + } + + List improperCardIdList = new List + { + CardId.FusionDeployment, CardId.BrandedBeast, CardId.AlbionTheShroudedDragon, CardId.BrandedOpening, CardId.GoldSarcophagus, + CardId.FoolishBurial, CardId.FallenOfAlbaz, CardId.BrandedInRed, _CardId.InfiniteImpermanence, CardId.TheBystialLubellion, + CardId.BrandedLost, CardId.SpringansKitt, CardId.GuidingQuemTheVirtuous, _CardId.CrossoutDesignator, _CardId.CalledByTheGrave, + CardId.TriBrigadeMercourier, _CardId.AshBlossom, _CardId.MaxxC + }; + foreach (int id in improperCardIdList) + { + ClientCard target = remainHandList.FirstOrDefault(c => c.IsCode(id)); + if (target != null) + { + discardList.Add(target); + } + } + if (discardList.Count > min) + { + discardList = discardList.Take(min).ToList(); + } + + return Util.CheckSelectCount(discardList, cards, min, max); + } + + // for The Bystial Lubellion + if (theBystialLubellionSelecting) + { + theBystialLubellionSelecting = false; + ClientCard target = TheBystialLubellionSpSummonCost(cards); + if (target != null) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } else + { + List targetList = new List(cards); + targetList.Sort(CardContainer.CompareCardAttack); + return Util.CheckSelectCount(targetList, cards, min, max); + } + } + + // for shrouded/saronir + if (albionTheShroudedDragonSelecting || (currentSolvingChain != null && currentSolvingChain.IsCode(CardId.BystialSaronir))) + { + // send retribution first + ClientCard retribution = cards.FirstOrDefault(c => c.IsCode(CardId.BrandedRetribution)); + if (retribution != null) + { + if (retribution.Location == CardLocation.Deck || Bot.GetGraveyardMonsters().Where(c => c.IsCode(albazFusionMonster)).Count() < 2) + { + return Util.CheckSelectCount(new List { retribution }, cards, min, max); + } + } + // send spells to recycle + if (Bot.HasInGraveyard(CardId.BrandedRetribution) || (Bot.HasInGraveyard(CardId.DespianTragedy) && !activatedCardIdList.Contains(CardId.DespianTragedy))) + { + Dictionary> deckCheckDict = new Dictionary>{ + {CardId.BrandedFusion, () => BrandedFusionActivateCheck()}, + {CardId.BrandedLost, () => { + if (Duel.Player == 0 && Duel.Phase >= DuelPhase.End) return false; + if (Bot.HasInHandOrInSpellZone(CardId.BrandedFusion) && BrandedFusionActivateCheck()) return true; + if (Bot.HasInHandOrInSpellZone(CardId.BrandedInWhite) && BrandedInWhiteActivateCheck()) return true; + if (Bot.HasInHandOrInSpellZone(CardId.BrandedInRed) && BrandedInRedActivateCheck() != null) return true; + if (!summoned && Bot.HasInHand(CardId.FallenOfAlbaz) && CheckAlbazFusion()) return true; + if ((Bot.HasInMonstersZone(CardId.BlazingCartesiaTheVirtuous) || (!summoned && Bot.HasInHand(CardId.BlazingCartesiaTheVirtuous)))) return true; + return false; + } }, + {CardId.BrandedInHighSpirits, BrandedInHighSpiritsActivateCheck}, + {CardId.BrandedInRed, () => BrandedInRedActivateCheck() != null }, + {CardId.BrandedInWhite, BrandedInWhiteActivateCheck }, + {CardId.BrandedRetribution, () => cards.Any(c => c.IsCode(CardId.BrandedRetribution) && c.Location == CardLocation.Removed) }, + {CardId.BrightestBlazingBrandedKing, () => Bot.GetMonsters().Any(c => c.IsFaceup() && c.IsCode(albazFusionMonster)) }, + {CardId.BrandedOpening, () => Bot.Hand.Count > 2 } + }; + foreach (KeyValuePair> pair in deckCheckDict) + { + ClientCard target = cards.FirstOrDefault(card => card.Location == CardLocation.Deck && card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + + // for abyss dragon + if (albionTheShroudedDragonSelecting && + FallenOfAlbazSetCheck() && (summoned || !Bot.HasInHand(new List { CardId.FallenOfAlbaz, CardId.BrandedInHighSpirits }))) + { + List checkIdList = new List { + CardId.BrandedRetribution, CardId.BrandedInHighSpirits, CardId.BrightestBlazingBrandedKing, CardId.BrandedInWhite, CardId.BrandedOpening, + CardId.BrandedInRed, CardId.BrandedBeast, CardId.BrandedLost + }; + if (!BrandedFusionActivateCheck()) + { + checkIdList.Add(CardId.BrandedFusion); + } + foreach (int checkId in checkIdList) + { + ClientCard target = cards.FirstOrDefault(c => c.Id == checkId); + if (target != null) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + } + + // send from deck + List checkList = new List { CardId.BrandedInHighSpirits, CardId.BrandedOpening, CardId.BrightestBlazingBrandedKing, CardId.BrandedBeast, CardId.BrandedLost }; + foreach (int checkId in checkList) + { + ClientCard target = cards.FirstOrDefault(c => c.IsCode(checkId) && c.Location == CardLocation.Deck); + if (target != null) + { + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + return Util.CheckSelectCount(ShuffleList(new List(cards)), cards, min, max); + } + + return base.OnSelectCard(cards, min, max, hint, cancelable); + } + + public override int OnSelectOption(IList options) + { + ClientCard currentSolvingChain = Duel.GetCurrentSolvingChainCard(); + if (currentSolvingChain != null) + { + // 1190=Add to Hand, 1152=Special Summon + if (options.Count == 2 && options.Contains(1190) && options.Contains(1152)) + { + if (currentSolvingChain.IsCode(CardId.BrandedOpening)) + { + return (CheckShouldNoMoreSpSummon() && !summoned && Duel.Player == 0) ? options.IndexOf(1190) : options.IndexOf(1152); + } + + if (fusionTarget != null && ( + currentSolvingChain.IsCode(CardId.DespianQuaeritis) + || currentSolvingChain.IsCode(CardId.TitanikladTheAshDragon) + || currentSolvingChain.IsCode(CardId.SprindTheIrondashDragon) + )) + { + if (fusionTarget.IsCode(CardId.FallenOfAlbaz)) + { + return CheckAlbazFusion() ? options.IndexOf(1152) : options.IndexOf(1190); + } + if (fusionTarget.IsCode(CardId.GuidingQuemTheVirtuous, CardId.SpringansKitt)) + { + return CheckShouldNoMoreSpSummon() ? options.IndexOf(1190) : options.IndexOf(1152); + } + if (fusionTarget.IsCode(CardId.AluberTheJesterOfDespia)) + { + return activatedCardIdList.Contains(CardId.AluberTheJesterOfDespia) ? options.IndexOf(1190) : options.IndexOf(1152); + } + return (CheckShouldNoMoreSpSummon() && !summoned) ? options.IndexOf(1190) : options.IndexOf(1152); + } + } + + // 1190=Add to Hand, 1153=Set + if (currentSolvingChain.IsCode(CardId.AlbionTheBrandedDragon) && fusionTarget != null) + { + if (fusionTarget.IsOriginalCode(CardId.BrandedInHighSpirits) && Duel.Player == 0) + { + return BrandedInHighSpiritsActivateCheck() ? options.IndexOf(1190) : options.IndexOf(1153); + } + if (fusionTarget.IsOriginalCode(CardId.BrandedInRed) && Duel.Player == 0) + { + if (nadirActivated) return options.IndexOf(1153); + return BrandedInRedActivateCheck() != null ? options.IndexOf(1190) : options.IndexOf(1153); + } + if (fusionTarget.Data != null) + { + bool setFlag = fusionTarget.Data.HasType(CardType.Trap); + setFlag |= fusionTarget.Data.HasType(CardType.QuickPlay) && Duel.Player == 0; + setFlag |= Bot.Hand.Count >= 6 && Duel.Player == 0; + return setFlag ? options.IndexOf(1153) : options.IndexOf(1190); + } + } + } + + return base.OnSelectOption(options); + } + + public override int OnSelectPlace(int cardId, int player, CardLocation location, int available) + { + ClientCard currentSovingChain = Duel.GetCurrentSolvingChainCard(); + if (currentSovingChain != null && currentSovingChain.Controller == 0 && currentSovingChain.IsCode(CardId.SprindTheIrondashDragon)) + { + return SprindTheIrondashDragonMoveZone(available, null); + } + + if (player == 0 && location == CardLocation.MonsterZone) + { + List zoneIdList = ShuffleList(new List { 5, 6 }); + zoneIdList.AddRange(ShuffleList(new List { 0, 2, 4 })); + zoneIdList.AddRange(ShuffleList(new List { 1, 3 })); + foreach (int zoneId in zoneIdList) + { + int zone = (int)System.Math.Pow(2, zoneId); + if ((available & zone) != 0 && Bot.MonsterZone[zoneId] == null) + { + return zone; + } + } + } + return base.OnSelectPlace(cardId, player, location, available); + } + + public override bool OnSelectYesNo(int desc) + { + if (desc == Util.GetStringId(CardId.BrandedInHighSpirits, 2)) + { + if (CheckWhetherWillbeRemoved()) return false; + if (fusionTarget != null && fusionTarget.IsOriginalCode(CardId.TriBrigadeMercourier)) + { + return !Bot.MonsterZone.Any(c => c != null && c.IsFaceup() && c.IsCode(albazFusionMonster)); + } + } + + if (desc == Util.GetStringId(CardId.RindbrummTheStrikingDragon, 2)) + { + bool checkFlag = Enemy.MonsterZone.Any(c => c != null); + checkFlag |= Bot.MonsterZone.Any(c => c != null && (c.IsOriginalCode(CardId.AluberTheJesterOfDespia) || c.IsOriginalCode(CardId.SpringansKitt))); + return checkFlag; + } + + if (desc == Util.GetStringId(CardId.DespianLuluwalilith, 2)) + { + bool checkFlag = Enemy.MonsterZone.Any(c => c != null && c.IsFaceup() && !c.IsDisabled()); + checkFlag |= Enemy.SpellZone.Any(c => c != null && c.IsFaceup() && !c.IsDisabled()); + return checkFlag; + } + + if (desc == Util.GetStringId(CardId.BrandedInRed, 0)) + { + // fix material list + brandedInRedMaterialList = brandedInRedMaterialList.Where(c => c != null && (c.Location == CardLocation.MonsterZone || c.Location == CardLocation.Hand)).ToList(); + + List materialList = Bot.MonsterZone.Where(c => c != null && c.Attack <= 2500 && !c.IsCode(cannotBeFusionMaterialIdList)).ToList(); + materialList.AddRange(Bot.Hand.Where(c => c.IsMonster() + && !(CheckWhetherCanSummon() && + ((!activatedCardIdList.Contains(CardId.AluberTheJesterOfDespia) && c.IsCode(CardId.AluberTheJesterOfDespia)) + || (!activatedCardIdList.Contains(CardId.SpringansKitt) && c.IsCode(CardId.SpringansKitt))) + ) + ) + ); + + BrandedInRedFusionCheck(Bot.ExtraDeck, 0, + materialList, brandedInRedMaterialList, + out ClientCard _fusionTarget, out _); + + return _fusionTarget != null; + } + + if (desc == Util.GetStringId(CardId.SprindTheIrondashDragon, 2)) + { + ClientCard currentSolvingChain = Duel.GetCurrentSolvingChainCard(); + if (currentSolvingChain != null) + { + int value = SprindTheIrondashDragonDestroyValue(currentSolvingChain.Sequence); + return value > 0; + } + } + + return base.OnSelectYesNo(desc); + } + + public override CardPosition OnSelectPosition(int cardId, IList positions) + { + ClientCard currentSolvingChain = Duel.GetCurrentSolvingChainCard(); + if (currentSolvingChain != null && currentSolvingChain.IsCode(CardId.AlbionTheSanctifireDragon)) + { + sanctifireSelectPositionCount++; + if (sanctifireSelectPositionCount >= 2) + { + if (Duel.Phase <= DuelPhase.Main2) + { + return CardPosition.FaceUpDefence; + } + } + } + + YGOSharp.OCGWrapper.NamedCard cardData = YGOSharp.OCGWrapper.NamedCard.Get(cardId); + if (cardData != null) + { + if (Duel.Turn == 1 || Duel.Phase >= DuelPhase.Main2) + { + bool turnDefense = false; + if (cardData.Attack <= cardData.Defense) + { + turnDefense = true; + } + if (turnDefense) + { + return CardPosition.FaceUpDefence; + } + } + if (Duel.Player == 1) + { + if (cardData.Defense >= cardData.Attack || Util.IsOneEnemyBetterThanValue(cardData.Attack, true)) + { + return CardPosition.FaceUpDefence; + } + } + int cardAttack = cardData.Attack; + int bestBotAttack = Math.Max(Util.GetBestAttack(Bot), cardAttack); + if (Util.IsAllEnemyBetterThanValue(bestBotAttack, true)) + { + return CardPosition.FaceUpDefence; + } + } + return base.OnSelectPosition(cardId, positions); + } + + public override void OnNewTurn() + { + if (Duel.Turn <= 1) + { + dimensionShifterCount = 0; + } + + summoned = false; + enemyActivateMaxxC = false; + enemyActivateLockBird = false; + enemyActivateInfiniteImpermanenceFromHand = false; + nadirActivated = false; + fusionToGYFlag = false; + spSummoningAlbaz = false; + cartesiaSummonGoal = 0; + sanctifireSelectPositionCount = 0; + quemSummonFlag = 0; + if (dimensionShifterCount > 0) dimensionShifterCount--; + cartesiaMaterialList.Clear(); + brandedInRedMaterialList.Clear(); + infiniteImpermanenceList.Clear(); + currentNegateCardList.Clear(); + currentDestroyCardList.Clear(); + sendToGYThisTurn.Clear(); + activatedCardIdList.Clear(); + enemyPlaceThisTurn.Clear(); + base.OnNewTurn(); + } + + public override void OnChaining(int player, ClientCard card) + { + Duel.LastChainTargets.Clear(); + if (card == null) return; + + if (player == 1) + { + if (card.IsCode(_CardId.InfiniteImpermanence)) + { + if (enemyActivateInfiniteImpermanenceFromHand) + { + enemyActivateInfiniteImpermanenceFromHand = false; + } + else + { + for (int i = 0; i < 5; ++i) + { + if (Enemy.SpellZone[i] == card) + { + infiniteImpermanenceList.Add(4 - i); + break; + } + } + } + } + } + base.OnChaining(player, card); + } + + public override void OnChainSolved(int chainIndex) + { + ClientCard currentCard = Duel.GetCurrentSolvingChainCard(); + if (currentCard != null) + { + // if activation is negated, it can activate again. + if (currentCard.Controller == 0) + { + List activateCheck = new List { CardId.NadirServant, CardId.FusionDeployment, CardId.BrandedFusion, CardId.BrandedInRed }; + if (currentCard.IsCode(activateCheck)) + { + activatedCardIdList.Add(currentCard.Id); + } + } + if (!Duel.IsCurrentSolvingChainNegated()) + { + if (currentCard.Controller == 1) + { + if (currentCard.IsCode(_CardId.MaxxC)) + enemyActivateMaxxC = true; + if (currentCard.IsCode(_CardId.LockBird)) + enemyActivateLockBird = true; + if (currentCard.IsCode(CardId.DimensionShifter)) + dimensionShifterCount = 2; + } + if (currentCard.Controller == 0 && currentCard.IsCode(CardId.NadirServant)) + { + nadirActivated = true; + } + } + } + fusionTarget = null; + selectedFusionMaterial.Clear(); + sanctifireSelectPositionCount = 0; + + base.OnChainSolved(chainIndex); + } + + public override void OnChainEnd() + { + cartesiaSummonGoal = 0; + cartesiaMaterialList.Clear(); + brandedInRedMaterialList.Clear(); + currentNegateCardList.Clear(); + currentDestroyCardList.Clear(); + enemyActivateInfiniteImpermanenceFromHand = false; + theBystialLubellionSelecting = false; + albionTheShroudedDragonSelecting = false; + spSummoningAlbaz = false; + for (int idx = enemyPlaceThisTurn.Count - 1; idx >= 0; idx--) + { + ClientCard checkTarget = enemyPlaceThisTurn[idx]; + if (checkTarget == null || (checkTarget.Location != CardLocation.SpellZone && checkTarget.Location != CardLocation.MonsterZone)) + { + enemyPlaceThisTurn.RemoveAt(idx); + } + } + if (quemSummonFlag > 0) quemSummonFlag--; + base.OnChainEnd(); + } + + public override void OnMove(ClientCard card, int previousControler, int previousLocation, int currentControler, int currentLocation) + { + if (previousControler == 1) + { + if (card != null) + { + if (card.IsCode(_CardId.InfiniteImpermanence) && previousLocation == (int)CardLocation.Hand && currentLocation == (int)CardLocation.SpellZone) + enemyActivateInfiniteImpermanenceFromHand = true; + } + } + if (card != null) + { + if (currentControler == 1 && (currentLocation == (int)CardLocation.MonsterZone || currentLocation == (int)CardLocation.SpellZone)) + { + enemyPlaceThisTurn.Add(card); + } + if (currentControler == 0) + { + ClientCard currentSolvingChain = Duel.GetCurrentSolvingChainCard(); + if (previousLocation == (int)CardLocation.Grave && currentLocation != (int)CardLocation.Grave) + { + sendToGYThisTurn.Remove(card); + } + if (currentLocation == (int)CardLocation.Grave) + { + if (card.HasType(CardType.Fusion)) fusionToGYFlag = true; + sendToGYThisTurn.Add(card); + } + if (currentLocation == (int)CardLocation.MonsterZone && card != null && card.IsCode(CardId.GuidingQuemTheVirtuous)) + { + quemSummonFlag = 2; + } + } + } + + base.OnMove(card, previousControler, previousLocation, currentControler, currentLocation); + } + + /// + /// Select spell/trap's place randomly to avoid InfiniteImpermanence and so on. + /// + /// Card to set(default current card) + /// Whether need to avoid InfiniteImpermanence + /// Whether need to avoid set in this place + public void SelectSTPlace(ClientCard card = null, bool avoidImpermanence = false, List avoidList = null) + { + if (card == null) card = Card; + List list = new List(); + for (int seq = 0; seq < 5; ++seq) + { + if (Bot.SpellZone[seq] == null) + { + if (card != null && card.Location == CardLocation.Hand && avoidImpermanence && infiniteImpermanenceList.Contains(seq)) continue; + if (avoidList != null && avoidList.Contains(seq)) continue; + list.Add(seq); + } + } + int n = list.Count; + while (n-- > 1) + { + int index = Program.Rand.Next(list.Count); + int nextIndex = (index + Program.Rand.Next(list.Count - 1)) % list.Count; + int tempInt = list[index]; + list[index] = list[nextIndex]; + list[nextIndex] = tempInt; + } + if (avoidImpermanence && Bot.GetMonsters().Any(c => c.IsFaceup() && !c.IsDisabled())) + { + foreach (int seq in list) + { + ClientCard enemySpell = Enemy.SpellZone[4 - seq]; + if (enemySpell != null && enemySpell.IsFacedown()) continue; + int zone = (int)System.Math.Pow(2, seq); + AI.SelectPlace(zone); + return; + } + } + foreach (int seq in list) + { + int zone = (int)System.Math.Pow(2, seq); + AI.SelectPlace(zone); + return; + } + AI.SelectPlace(0); + } + + public bool TheBystialLubellionSpSummon() + { + if (Card.Location == CardLocation.Hand) + { + return false; + } + ClientCard costTarget = TheBystialLubellionSpSummonCost(Bot.GetMonsters()); + if (costTarget != null) + { + theBystialLubellionSelecting = true; + activatedCardIdList.Add(Card.Id - 1); + return true; + } + return false; + } + + public ClientCard TheBystialLubellionSpSummonCost(IList costList) + { + Dictionary> checkDict = new Dictionary>{ + {CardId.AlbionTheBrandedDragon, (card) => sendToGYThisTurn.All(c => !c.IsCode(CardId.AlbionTheBrandedDragon))}, + {CardId.BystialSaronir, (card) => !activatedCardIdList.Contains(CardId.BystialSaronir + 1) && !CheckWhetherWillbeRemoved() }, + {CardId.TitanikladTheAshDragon, (card) => Util.IsTurn1OrMain2() || card.GetDefensePower() < 2500 }, + {CardId.AlbaLenatusTheAbyssDragon, (card) => Util.IsTurn1OrMain2() || card.IsDisabled() || card.GetDefensePower() < 2500 }, + {CardId.AlbionTheShroudedDragon, (card) => Util.IsTurn1OrMain2() || card.GetDefensePower() < 2500 }, + {CardId.BorreloadFuriousDragon, (card) => card.IsDisabled() && CheckRemainInDeck(CardId.BrandedBeast, CardId.BrandedLost) > 0 }, + }; + + foreach (KeyValuePair> pair in checkDict) + { + List targetList = costList.Where(card => card.IsCode(pair.Key)).ToList(); + foreach (ClientCard target in targetList) + { + if (target != null && pair.Value(target)) + { + return target; + } + } + } + return null; + } + + public bool TheBystialLubellionActivate() + { + if (CheckWhetherNegated(true, Card.Location == CardLocation.MonsterZone, CardType.Monster)) return false; + if (Card.Location == CardLocation.Hand) + { + activatedCardIdList.Add(Card.Id); + } else + { + activatedCardIdList.Add(Card.Id + 1); + } + return true; + } + + public bool AlbionTheShroudedDragonActivate() + { + if (CheckWhetherNegated(true, false, CardType.Monster) || CheckWhetherWillbeRemoved()) return false; + bool checkFlag = CheckRemainInDeck(CardId.BrandedRetribution, CardId.BrandedOpening, CardId.BrightestBlazingBrandedKing, CardId.BrandedInHighSpirits) > 0; + if (Bot.HasInGraveyard(CardId.BrandedRetribution)) + { + checkFlag |= CheckRemainInDeck(CardId.BrandedFusion, CardId.BrandedBeast, CardId.BrandedInRed, CardId.BrandedInWhite, CardId.BrandedLost) > 0; + } + if (Bot.HasInSpellZone(CardId.BrandedBeast)) + { + checkFlag |= CheckRemainInDeck(CardId.BrandedLost) > 0; + } + if (Card.Location == CardLocation.Grave) + { + checkFlag |= CheckRemainInDeck(CardId.BrandedInWhite) > 0; + } + // for abyss dragon + if (FallenOfAlbazSetCheck() && (summoned || !Bot.HasInHand(new List { CardId.FallenOfAlbaz, CardId.BrandedInHighSpirits }))) + { + checkFlag |= Bot.HasInHand(new List { CardId.BrandedBeast, CardId.BrandedInHighSpirits, CardId.BrandedInWhite, CardId.BrandedInRed, CardId.BrandedLost, CardId.BrandedOpening, CardId.BrandedRetribution, CardId.BrightestBlazingBrandedKing }); + } + + if (checkFlag) + { + activatedCardIdList.Add(Card.Id); + albionTheShroudedDragonSelecting = true; + return true; + } + return false; + } + + public bool BystialSaronirActivate() + { + if (CheckWhetherNegated(true, false, CardType.Monster)) return false; + // banish & spsummon + if (Card.Location == CardLocation.Hand) + { + // banish enemy target + if (Util.GetLastChainCard() != null && Duel.LastChainPlayer == 1) + { + List chainTargetList = Duel.LastChainTargets.Where(c => CheckBystialCanBanish(c)).ToList(); + if (chainTargetList.Count > 0) + { + AI.SelectCard(chainTargetList); + currentDestroyCardList.Add(chainTargetList[0]); + activatedCardIdList.Add(Card.Id); + return true; + } + } + + List enemyChainList = Duel.CurrentChain.Where(c => c != null && c.Controller == 1 && CheckBystialCanBanish(c) && !currentDestroyCardList.Contains(c)) + .OrderByDescending(c => c.GetDefensePower()).ToList(); + if (enemyChainList.Count > 0) + { + AI.SelectCard(enemyChainList); + currentDestroyCardList.Add(enemyChainList[0]); + activatedCardIdList.Add(Card.Id); + return true; + } + + // banish cards with effect + if (!CheckShouldNoMoreSpSummon()) + { + ClientCard mercourier = Bot.Graveyard.FirstOrDefault(c => c != null && c.IsCode(CardId.TriBrigadeMercourier)); + if (mercourier != null && !activatedCardIdList.Contains(CardId.TriBrigadeMercourier + 1)) + { + AI.SelectCard(mercourier); + currentDestroyCardList.Add(mercourier); + activatedCardIdList.Add(Card.Id); + return true; + } + ClientCard tragedy = Bot.Graveyard.FirstOrDefault(c => c != null && c.IsCode(CardId.DespianTragedy)); + if (tragedy != null && !activatedCardIdList.Contains(CardId.DespianTragedy)) + { + AI.SelectCard(tragedy); + currentDestroyCardList.Add(tragedy); + activatedCardIdList.Add(Card.Id); + return true; + } + if (Bot.HasInGraveyard(CardId.TheBystialLubellion) && !activatedCardIdList.Contains(CardId.TheBystialLubellion) + && Duel.Player == 0 && CheckRemainInDeck(CardId.BrandedLost, CardId.BrandedBeast) > 0 + && CurrentTiming == -1) + { + List targetList = Enemy.Graveyard.Where(c => c != null && CheckBystialCanBanish(c)).OrderByDescending(card => card.Attack).ToList(); + targetList.AddRange(Bot.Graveyard + .Where(c => c != null && CheckBystialCanBanish(c) && !c.IsCode(CardId.TheBystialLubellion) && !CheckWhetherShouldKeepInGrave(c)) + .OrderBy(card => card.Attack).ToList() + ); + if (targetList.Count > 0) + { + AI.SelectCard(targetList); + currentDestroyCardList.Add(targetList[0]); + activatedCardIdList.Add(Card.Id); + return true; + } + } + } + + // defense + if (Bot.UnderAttack && Bot.BattlingMonster == null) + { + List targetList = Enemy.Graveyard.Where(c => CheckBystialCanBanish(c)).OrderByDescending(c => c.GetDefensePower()).ToList(); + targetList.AddRange(Bot.Graveyard.Where(c => CheckBystialCanBanish(c)).OrderBy(c => c.GetDefensePower())); + if (targetList.Count > 0) + { + AI.SelectCard(targetList); + currentDestroyCardList.Add(targetList[0]); + activatedCardIdList.Add(Card.Id); + return true; + } + } + + // trigger beast + if (Duel.Player == 1 && (Duel.Phase == DuelPhase.Main1 || Duel.Phase == DuelPhase.Main2) + && !activatedCardIdList.Contains(CardId.BrandedBeast) && Bot.SpellZone.Any(c => c != null && c.IsCode(CardId.BrandedBeast) && (c.IsFacedown() || !c.IsDisabled())) + && !Bot.MonsterZone.Any(c => c != null && c.IsFaceup() && c.HasSetcode(SetcodeBystial))) + { + List dangerList = GetProblematicEnemyCardList(true, false, CardType.Trap); + if (dangerList.Count > 0) + { + List targetList = Enemy.Graveyard.Where(c => CheckBystialCanBanish(c)).OrderByDescending(c => c.GetDefensePower()).ToList(); + targetList.AddRange(Bot.Graveyard.Where(c => CheckBystialCanBanish(c)).OrderBy(c => c.GetDefensePower())); + if (targetList.Count > 0) + { + AI.SelectCard(targetList); + currentDestroyCardList.Add(targetList[0]); + activatedCardIdList.Add(Card.Id); + return true; + } + } + } + + } + // send to GY + if (Card.Location == CardLocation.Grave && !CheckWhetherWillbeRemoved()) + { + if (Bot.HasInGraveyard(CardId.BrandedRetribution)) + { + activatedCardIdList.Add(Card.Id + 1); + return true; + } else if (CheckRemainInDeck(CardId.TheBystialLubellion, CardId.BrandedRetribution, CardId.BrandedInHighSpirits, CardId.BrightestBlazingBrandedKing, CardId.BrandedOpening) > 0) + { + activatedCardIdList.Add(Card.Id + 1); + return true; + } + } + return false; + } + + public bool CheckBystialCanBanish(ClientCard c) + { + return c != null && c.Location == CardLocation.Grave && c.IsMonster() && c.HasAttribute(CardAttribute.Light | CardAttribute.Dark); + } + + public bool AluberTheJesterOfDespiaSummon() + { + if (CheckWhetherNegated(true, true, CardType.Monster) || enemyActivateLockBird || activatedCardIdList.Contains(Card.Id)) return false; + summoned = true; + return true; + } + + public bool AluberTheJesterOfDespiaActivate() + { + // search + if (Card.Location == CardLocation.MonsterZone) + { + if (CheckWhetherNegated(true, true, CardType.Monster)) return false; + activatedCardIdList.Add(Card.Id); + return true; + } + // spsummon + else + { + List targetCardList = GetMonsterListForTargetNegate(true, CardType.Monster); + ClientCard lastChainCard = Util.GetLastChainCard(); + // chain to protect + if (lastChainCard != null && lastChainCard.Controller == 0) + { + AI.SelectCard(targetCardList); + activatedCardIdList.Add(Card.Id); + return true; + } + if (CheckWhetherNegated(true, false, CardType.Monster)) return false; + AI.SelectCard(targetCardList); + activatedCardIdList.Add(Card.Id); + return true; + } + } + + public bool FallenOfAlbazSummon() + { + if (CheckAlbazFusion(Card)) + { + summoned = true; + return true; + } + return false; + } + + public bool FallenOfAlbazSet() + { + if (FallenOfAlbazSetCheck()) + { + summoned = true; + return true; + } + return false; + } + + public bool FallenOfAlbazSetCheck() + { + if (!Bot.HasInExtra(CardId.AlbaLenatusTheAbyssDragon) || nadirActivated) return false; + // check dangerous dragon + if (!Bot.HasInSpellZone(CardId.BrandedLost, true, true) || Bot.GetHandCount() < 2) + { + foreach (int dangerId in dangerousDragonIdList) + { + if (Enemy.HasInMonstersZone(dangerId, true, false, true)) + { + return true; + } + } + } + // check dragon count + int dragonCount = Enemy.GetMonsters().Where(c => c != null && c.IsFaceup() && !c.IsCode(cannotBeFusionMaterialIdList) && c.HasRace(CardRace.Dragon)).Count(); + if (dragonCount > 1) + { + return true; + } + return false; + } + + /// + /// Check whether should call albaz. + /// + /// + /// + public bool CheckAlbazFusion(ClientCard exceptCost = null) { + return CheckAlbazFusion(exceptCost, out _); + } + + public bool CheckAlbazFusion(ClientCard exceptCost, out List enemyMonsterList) + { + enemyMonsterList = null; + int costHandCount = Bot.Hand.Where(c => c != exceptCost).Count(); + if (costHandCount <= 0 || Enemy.GetMonsterCount() == 0) return false; + if (CheckWhetherNegated(true, true, CardType.Monster) || activatedCardIdList.Contains(CardId.FallenOfAlbaz) || nadirActivated) return false; + if (!Bot.HasInMonstersZone(CardId.MirrorjadeTheIcebladeDragon, faceUp: true) && !Bot.HasInSpellZone(CardId.MirrorjadeTheIcebladeDragon) + && Bot.HasInExtra(CardId.MirrorjadeTheIcebladeDragon)) + { + ClientCard target = Enemy.GetMonsters() + .Where(c => c.IsFaceup() && !c.IsCode(cannotBeFusionMaterialIdList) && c.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link)) + .OrderByDescending(c => c.GetDefensePower()).FirstOrDefault(); + if (target != null) + { + enemyMonsterList = new List { target }; + return true; + } + } + if (Bot.HasInExtra(CardId.AlbaLenatusTheAbyssDragon)) + { + List targetList = Enemy.GetMonsters().Where(c => c.IsFaceup() && !c.IsCode(cannotBeFusionMaterialIdList) && c.HasRace(CardRace.Dragon)) + .OrderByDescending(c => c.GetDefensePower()).ToList(); + if (targetList.Count > 0) + { + enemyMonsterList = targetList; + return true; + } + } + if (Bot.HasInExtra(CardId.AlbionTheBrandedDragon)) + { + ClientCard target = Enemy.GetMonsters() + .Where(c => c.IsFaceup() && !c.IsCode(cannotBeFusionMaterialIdList) && c.HasAttribute(CardAttribute.Light)) + .OrderByDescending(c => c.GetDefensePower()).FirstOrDefault(); + if (target != null) + { + enemyMonsterList = new List { target }; + return true; + } + } + if (Bot.HasInExtra(CardId.AlbionTheSanctifireDragon)) + { + ClientCard target = Enemy.GetMonsters() + .Where(c => c.IsFaceup() && !c.IsCode(cannotBeFusionMaterialIdList) && c.HasAttribute(CardAttribute.Light) && c.HasRace(CardRace.SpellCaster)) + .OrderByDescending(c => c.GetDefensePower()).FirstOrDefault(); + if (target != null) + { + enemyMonsterList = new List { target }; + return true; + } + } + if (Bot.HasInExtra(CardId.LubellionTheSearingDragon)) + { + ClientCard target = Enemy.GetMonsters() + .Where(c => c.IsFaceup() && !c.IsCode(cannotBeFusionMaterialIdList) && c.HasAttribute(CardAttribute.Dark)) + .OrderByDescending(c => c.GetDefensePower()).FirstOrDefault(); + if (costHandCount >= 2 && target != null) + { + enemyMonsterList = new List { target }; + return true; + } + } + if (Bot.HasInExtra(CardId.BorreloadFuriousDragon)) + { + ClientCard target = Enemy.GetMonsters() + .Where(c => c.IsFaceup() && !c.IsCode(cannotBeFusionMaterialIdList) && c.HasRace(CardRace.Dragon) && c.HasAttribute(CardAttribute.Dark)) + .OrderByDescending(c => c.GetDefensePower()).FirstOrDefault(); + if (target != null) + { + enemyMonsterList = new List { target }; + return true; + } + } + if (Bot.HasInExtra(CardId.TitanikladTheAshDragon)) + { + ClientCard target = Enemy.GetMonsters() + .Where(c => c.IsFaceup() && !c.IsCode(cannotBeFusionMaterialIdList) && c.Attack >= 2500) + .OrderByDescending(c => c.GetDefensePower()).FirstOrDefault(); + if (target != null) + { + enemyMonsterList = new List { target }; + return true; + } + } + if (Bot.HasInExtra(CardId.RindbrummTheStrikingDragon)) + { + ClientCard target = Enemy.GetMonsters() + .Where(c => c.IsFaceup() && !c.IsCode(cannotBeFusionMaterialIdList) && c.HasRace(CardRace.Beast | CardRace.BeastWarrior | CardRace.WindBeast)) + .OrderByDescending(c => c.GetDefensePower()).FirstOrDefault(); + if (target != null) + { + enemyMonsterList = new List { target }; + return true; + } + } + if (Bot.HasInExtra(CardId.SprindTheIrondashDragon)) + { + ClientCard target = Enemy.GetMonsters() + .Where(c => c != null && c.IsFaceup() && !c.IsCode(cannotBeFusionMaterialIdList) && enemyPlaceThisTurn.Contains(c) && c.IsSpecialSummoned + && c.GetDefensePower() >= Util.GetBestPower(Bot)) + .OrderByDescending(c => c.GetDefensePower()).FirstOrDefault(); + if (target != null) + { + enemyMonsterList = new List { target }; + return true; + } + } + + return false; + } + + public bool FallenOfAlbazActivate() + { + if (Bot.HasInExtra(CardId.AlbaLenatusTheAbyssDragon) && Enemy.MonsterZone.Any(c => c != null && c.IsFaceup() && c.IsCode(dangerousDragonIdList))) return false; + if (CheckAlbazFusion()) + { + activatedCardIdList.Add(Card.Id); + return true; + } + return false; + } + + public bool SpringansKittSummon() + { + if (CheckWhetherNegated(true, true, CardType.Monster) || enemyActivateLockBird || activatedCardIdList.Contains(Card.Id + 1)) return false; + summoned = true; + return true; + } + + public bool SpringansKittActivate() + { + // spsummon + if (Card.Location == CardLocation.Hand) + { + if (CheckWhetherNegated(true, true, CardType.Monster)) return false; + if (CheckShouldNoMoreSpSummon()) + { + bool skipFlag = !summoned; + skipFlag |= activatedCardIdList.Contains(CardId.BrandedFusion); + skipFlag |= Bot.MonsterZone.Any(c => c != null && c.IsFaceup() && c.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link)); + if (skipFlag) + { + return false; + } + } + activatedCardIdList.Add(Card.Id); + return true; + } + // search + if (Card.Location == CardLocation.MonsterZone) + { + if (CheckWhetherNegated(true, true, CardType.Monster)) return false; + activatedCardIdList.Add(Card.Id + 1); + return true; + } + + return false; + } + + public bool GuidingQuemTheVirtuousSummon() + { + if (CheckWhetherNegated(true, true, CardType.Monster) || CheckWhetherWillbeRemoved()) return false; + if (activatedCardIdList.Contains(Card.Id)) return false; + summoned = true; + return true; + } + + public bool GuidingQuemTheVirtuousSummonForSearch() + { + if (CheckWhetherNegated(true, true, CardType.Monster) || CheckWhetherWillbeRemoved()) return false; + if (activatedCardIdList.Contains(Card.Id)) return false; + if (Bot.HasInGraveyard(CardId.BrandedRetribution) && CheckRemainInDeck(CardId.BrandedFusion, CardId.BrandedLost, CardId.BrandedInWhite, CardId.BrandedInRed) > 0) + { + summoned = true; + return true; + } + if (Bot.HasInGraveyard(new[] { CardId.BrandedFusion, CardId.BrandedLost, CardId.BrandedBeast }) && CheckRemainInDeck(CardId.BrandedRetribution) > 0) + { + summoned = true; + return true; + } + return false; + } + + public bool GuidingQuemTheVirtuousActivate() + { + int desc = -1; + if (ActivateDescription >= Util.GetStringId(CardId.GuidingQuemTheVirtuous, 0)) + { + desc = ActivateDescription - Util.GetStringId(CardId.GuidingQuemTheVirtuous, 0); + } + Logger.DebugWriteLine("Guiding desc: " + desc.ToString()); + Logger.DebugWriteLine("Guiding timing: " + CurrentTiming.ToString()); + Logger.DebugWriteLine("Guiding flag: " + quemSummonFlag.ToString()); + + // spsummon + if ((ActivateDescription == -1 && quemSummonFlag == 0) || ActivateDescription == Util.GetStringId(CardId.GuidingQuemTheVirtuous, 1)) + { + if (CheckWhetherNegated(true, true, CardType.Monster)) return false; + List>> checkList = new List>> + { + new KeyValuePair>(CardId.AlbionTheSanctifireDragon, (c) => c.IsCanRevive() && !activatedCardIdList.Contains(CardId.AlbionTheSanctifireDragon) ), + new KeyValuePair>(CardId.MirrorjadeTheIcebladeDragon, (c) => c.IsCanRevive() ), + new KeyValuePair>(CardId.FallenOfAlbaz, (c) => + { + bool albazCanFusionFlag = CheckAlbazFusion(null, out List materialList); + if (albazCanFusionFlag && !Util.ChainContainsCard(new[] {CardId.AlbionTheBrandedDragon, CardId.LubellionTheSearingDragon}) && !spSummoningAlbaz) + { + bool albazFlag = materialList.Count > 1; + if (materialList.Count > 0) + { + ClientCard material = materialList[0]; + albazFlag |= material.HasType(CardType.Ritual | CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link); + albazFlag |= material.IsFloodgate() || material.IsOneForXyz() || Util.GetWorstBotMonster().GetDefensePower() < material.Attack; + } + return albazFlag; + } + return false; + } ), + new KeyValuePair>(CardId.AlbionTheBrandedDragon, (c) => c.IsCanRevive() && Bot.HasInSpellZone(CardId.BrandedBeast) + && Bot.MonsterZone.Any(oc => oc != null && oc.IsFaceup() && oc.HasSetcode(SetcodeBystial)) ), + new KeyValuePair>(CardId.BlazingCartesiaTheVirtuous, (c) => Duel.Player == 0 || !activatedCardIdList.Contains(CardId.BlazingCartesiaTheVirtuous + 1) ), + new KeyValuePair>(CardId.TriBrigadeMercourier, (c) => Bot.MonsterZone.Any(oc => oc != null && oc.IsFaceup() && oc.IsCode(albazFusionMonster)) ), + new KeyValuePair>(CardId.AlbionTheSanctifireDragon, (c) => c.IsCanRevive() ), + new KeyValuePair>(CardId.SpringansKitt, (c) => true ) + }; + foreach (KeyValuePair> pair in checkList) + { + ClientCard target = Bot.Graveyard.FirstOrDefault(c => c != null && c.IsOriginalCode(pair.Key) && pair.Value(c)); + if (target != null) + { + if (target.IsOriginalCode(CardId.FallenOfAlbaz)) + { + spSummoningAlbaz = true; + } + AI.SelectCard(target); + activatedCardIdList.Add(Card.Id + 1); + return true; + } + } + } + // send to GY + if ((ActivateDescription == -1 && quemSummonFlag > 0) || ActivateDescription == Util.GetStringId(CardId.GuidingQuemTheVirtuous, 0)) + { + if (CheckWhetherNegated(true, true, CardType.Monster) || CheckWhetherWillbeRemoved()) return false; + quemSummonFlag = 0; + activatedCardIdList.Add(Card.Id); + return true; + } + return false; + } + + public bool BlazingCartesiaTheVirtuousSummon() + { + if (CheckWhetherNegated(true, true, CardType.Monster)) return false; + bool checkFlag = Bot.HasInHandOrInSpellZone(CardId.BrandedOpening) && !activatedCardIdList.Contains(CardId.AluberTheJesterOfDespia) && CheckRemainInDeck(CardId.AluberTheJesterOfDespia) > 0; + checkFlag |= Bot.HasInHand(CardId.AlbionTheShroudedDragon) && !activatedCardIdList.Contains(CardId.AlbionTheShroudedDragon); + checkFlag |= Bot.HasInHandOrHasInMonstersZone(CardId.BystialSaronir) && !activatedCardIdList.Contains(CardId.BystialSaronir + 1); + if (Bot.HasInExtra(CardId.GranguignolTheDuskDragon)) + { + bool hasMaterial = Bot.Hand.Any(c => c != Card && c.Attack < 2000 && c.HasAttribute(CardAttribute.Light | CardAttribute.Dark)); + hasMaterial |= Bot.MonsterZone.Any(c => c != null && !c.IsCode(cannotBeFusionMaterialIdList) && c.Attack < 2000 && c.HasAttribute(CardAttribute.Light | CardAttribute.Dark)); + checkFlag |= hasMaterial; + } + + if (checkFlag) + { + summoned = true; + return true; + } + + return false; + } + + public bool BlazingCartesiaTheVirtuousActivate() + { + // sp summon + if (Card.Location == CardLocation.Hand) + { + if (CheckShouldNoMoreSpSummon() || CheckWhetherNegated(true, true, CardType.Monster)) return false; + activatedCardIdList.Add(Card.Id); + return true; + } + // fusion + if (Card.Location == CardLocation.MonsterZone) + { + if (CheckWhetherNegated(true, true, CardType.Monster)) return false; + if (Duel.CurrentChain.Any(c => c != null && c.Controller == 0 && c.IsCode(CardId.BrandedInRed))) return false; + List materialList = Bot.MonsterZone.Where(c => c != null && c.Attack <= 2500 && !c.IsCode(cannotBeFusionMaterialIdList)).ToList(); + materialList.AddRange(Bot.Hand.Where(c => c.IsMonster() + && !(CheckWhetherCanSummon() && + ((!activatedCardIdList.Contains(CardId.AluberTheJesterOfDespia) && c.IsCode(CardId.AluberTheJesterOfDespia)) + || (!activatedCardIdList.Contains(CardId.SpringansKitt) && c.IsCode(CardId.SpringansKitt))) + ) + ) + ); + + // escape target + ClientCard lastCahinCard = Util.GetLastChainCard(); + if (lastCahinCard != null && Duel.LastChainPlayer == 1) + { + List chainTargetList = Duel.LastChainTargets.Where(c => c.Controller == 0 && c.Location == CardLocation.MonsterZone + && (!c.IsCode(cannotBeFusionMaterialIdList) || c.Attack <= 2500)).ToList(); + if (chainTargetList.Count > 0) + { + if (lastCahinCard.IsCode(targetNegateIdList)) + { + chainTargetList = chainTargetList.Where(c => c.Attack <= 2500).ToList(); + } + BlazingCartesiaTheVirtuousFusionCheck(Bot.ExtraDeck, 0, materialList, chainTargetList, + out ClientCard _fusionTarget, out List usedMaterialList); + + if (_fusionTarget != null) + { + Logger.DebugWriteLine("cartesia prepare fusion1: " + _fusionTarget.Name); + cartesiaMaterialList.AddRange(usedMaterialList.Intersect(chainTargetList)); + activatedCardIdList.Add(Card.Id + 1); + return true; + } + } + } + + // fusion shrouded + bool skipShroudedFlag = CheckWhetherCanSummon() && !activatedCardIdList.Contains(CardId.AluberTheJesterOfDespia) && Bot.HasInHand(CardId.AluberTheJesterOfDespia); + skipShroudedFlag |= CheckWhetherCanSummon() && !activatedCardIdList.Contains(CardId.SpringansKitt) && Bot.HasInHand(CardId.SpringansKitt); + if (!skipShroudedFlag) + { + ClientCard shrouded = Duel.CurrentChain.FirstOrDefault(c => c.Controller == 0 && c.Location == CardLocation.Hand && c.IsOriginalCode(CardId.AlbionTheShroudedDragon)); + if (shrouded != null) + { + BlazingCartesiaTheVirtuousFusionCheck(Bot.ExtraDeck, 0, materialList, new List { shrouded }, + out ClientCard _fusionTarget, out List usedMaterialList); + + if (_fusionTarget != null) + { + Logger.DebugWriteLine("cartesia prepare fusion2: " + _fusionTarget.Name); + cartesiaMaterialList.AddRange(usedMaterialList.Intersect(new List { shrouded })); + activatedCardIdList.Add(Card.Id + 1); + return true; + } + } + } + + bool shouldActivateFlag = Duel.Player == 0 && !CheckShouldNoMoreSpSummon() || Duel.Player == 1; + + // summon mirrorjade + bool checkMirrorJadeFlag = !(Bot.HasInMonstersZone(CardId.MirrorjadeTheIcebladeDragon, faceUp: true) || Bot.HasInSpellZone(CardId.MirrorjadeTheIcebladeDragon, faceUp: true)) + && shouldActivateFlag; + if (checkMirrorJadeFlag) + { + BlazingCartesiaTheVirtuousFusionCheck(Bot.ExtraDeck, CardId.MirrorjadeTheIcebladeDragon, materialList, null, + out ClientCard _fusionTarget, out _); + + if (_fusionTarget != null) + { + Logger.DebugWriteLine("cartesia prepare fusion3: " + _fusionTarget.Name); + cartesiaSummonGoal = CardId.MirrorjadeTheIcebladeDragon; + activatedCardIdList.Add(Card.Id + 1); + return true; + } + } + + // summon dusk dragon + if (shouldActivateFlag && Duel.Player == 0) + { + Dictionary> checkDict = new Dictionary> + { + {CardId.BystialSaronir, () => !activatedCardIdList.Contains(CardId.BystialSaronir + 1) && !DefaultCheckWhetherCardIdIsNegated(CardId.BystialSaronir) }, + {CardId.DespianTragedy, () => !activatedCardIdList.Contains(CardId.DespianTragedy) && !DefaultCheckWhetherCardIdIsNegated(CardId.DespianTragedy) } + }; + foreach (KeyValuePair> pair in checkDict) + { + ClientCard targetMaterial = materialList.FirstOrDefault(c => c.IsCode(pair.Key)); + if (targetMaterial != null && pair.Value()) + { + BlazingCartesiaTheVirtuousFusionCheck(Bot.ExtraDeck, CardId.GranguignolTheDuskDragon, materialList, new List { targetMaterial }, + out ClientCard _fusionTarget, out List usedMaterialList); + if (_fusionTarget != null) + { + Logger.DebugWriteLine("cartesia prepare fusion4: " + _fusionTarget.Name); + cartesiaSummonGoal = CardId.GranguignolTheDuskDragon; + cartesiaMaterialList.Add(targetMaterial); + activatedCardIdList.Add(Card.Id + 1); + return true; + } + } + } + } + + // summon sanctifire + if (shouldActivateFlag) + { + BlazingCartesiaTheVirtuousFusionCheck(Bot.ExtraDeck, CardId.AlbionTheSanctifireDragon, materialList, new List { Card}, + out ClientCard _fusionTarget, out List usedMaterialList); + if (_fusionTarget != null) + { + Logger.DebugWriteLine("cartesia prepare fusion5: " + _fusionTarget.Name); + cartesiaSummonGoal = CardId.AlbionTheSanctifireDragon; + cartesiaMaterialList.Add(Card); + activatedCardIdList.Add(Card.Id + 1); + return true; + } + } + + if (shouldActivateFlag && GetProblematicEnemyMonster(0, true, true, CardType.Monster) != null) + { + BlazingCartesiaTheVirtuousFusionCheck(Bot.ExtraDeck, CardId.BorreloadFuriousDragon, materialList, null, + out ClientCard _fusionTarget, out _); + + if (_fusionTarget != null) + { + Logger.DebugWriteLine("cartesia prepare fusion6: " + _fusionTarget.Name); + cartesiaSummonGoal = CardId.BorreloadFuriousDragon; + activatedCardIdList.Add(Card.Id + 1); + return true; + } + } + + if (shouldActivateFlag) + { + bool checkFlag = Duel.Player == 0 && CurrentTiming == -1; + checkFlag |= Duel.Player == 1 && (CurrentTiming & hintTimingMainEnd) != 0; + if (checkFlag) + { + BlazingCartesiaTheVirtuousFusionCheck(Bot.ExtraDeck, 0, materialList, null, + out ClientCard _fusionTarget, out _); + + if (_fusionTarget != null) + { + Logger.DebugWriteLine("cartesia prepare fusion7: " + _fusionTarget.Name); + activatedCardIdList.Add(Card.Id + 1); + return true; + } + } + } + } + return false; + } + + public bool BlazingCartesiaTheVirtuousActivateInGrave() + { + // recycle + if (Card.Location == CardLocation.Grave) + { + if (CheckWhetherNegated(true, false, CardType.Monster)) return false; + activatedCardIdList.Add(Card.Id + 2); + return true; + } + return false; + } + + public void BlazingCartesiaTheVirtuousFusionCheck( + IList canSummonList, int mustSummonId, + List materialList, List mustMaterialList, + out ClientCard fusionTarget, out List selectedFusionMaterialList) + { + fusionTarget = null; + selectedFusionMaterialList = new List(); + + Dictionary>> checkDict = new Dictionary>> + { + {CardId.GranguignolTheDuskDragon, new List>{ + (c) => c.IsCode(CardId.BlazingCartesiaTheVirtuous), + (c) => !c.IsCode(cannotBeFusionMaterialIdList) && c.HasAttribute(CardAttribute.Light | CardAttribute.Dark) + } }, + {CardId.AlbionTheSanctifireDragon, new List>{ + (c) => c.IsCode(CardId.FallenOfAlbaz), + (c) => !c.IsCode(cannotBeFusionMaterialIdList) && c.HasAttribute(CardAttribute.Light) && c.HasRace(CardRace.SpellCaster) + } }, + {CardId.MirrorjadeTheIcebladeDragon, new List> + { + (c) => c.IsCode(CardId.FallenOfAlbaz), + (c) => !c.IsCode(cannotBeFusionMaterialIdList) && c.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link) + } }, + {CardId.AlbionTheBrandedDragon, new List> + { + (c) => c.IsCode(CardId.FallenOfAlbaz), + (c) => !c.IsCode(cannotBeFusionMaterialIdList) && c.HasAttribute(CardAttribute.Light) + } }, + {CardId.LubellionTheSearingDragon, new List> + { + (c) => c.IsCode(CardId.FallenOfAlbaz), + (c) => !c.IsCode(cannotBeFusionMaterialIdList) && c.HasAttribute(CardAttribute.Dark) + } }, + {CardId.DespianQuaeritis, new List> + { + (c) => c.HasSetcode(SetcodeDespain), + (c) => !c.IsCode(cannotBeFusionMaterialIdList) && c.HasAttribute(CardAttribute.Light | CardAttribute.Dark) + } }, + {CardId.BorreloadFuriousDragon, new List> + { + (c) => !c.IsCode(cannotBeFusionMaterialIdList) && c.HasAttribute(CardAttribute.Dark) && c.HasRace(CardRace.Dragon), + (c) => !c.IsCode(cannotBeFusionMaterialIdList) && c.HasAttribute(CardAttribute.Dark) && c.HasRace(CardRace.Dragon) + } } + }; + Dictionary> extraCheckDict = new Dictionary> + { + {CardId.AlbionTheSanctifireDragon, (c1, c2) => + { + int reviveCount = Bot.Graveyard.Count(c => c != null && c.IsMonster() && c.IsCanRevive()); + reviveCount += Enemy.Graveyard.Count(c => c != null && c.IsMonster() && c.IsCanRevive()); + if (!CheckWhetherWillbeRemoved() || + (CurrentTiming & hintTimingMainEnd) > 0 && Util.GetOneEnemyBetterThanValue(Card.GetDefensePower()) != null + && Util.GetOneEnemyBetterThanValue(3000) == null) + { + reviveCount += 2; + } + return reviveCount >= 2; + } }, + {CardId.LubellionTheSearingDragon, (c1, c2) => Bot.Hand.Count(c => c != c1 && c != c2) > 0 }, + {CardId.MirrorjadeTheIcebladeDragon, (c1, c2) => !CheckWhetherWillbeRemoved() && + !Bot.HasInMonstersZone(CardId.MirrorjadeTheIcebladeDragon, faceUp: true) && !Bot.HasInSpellZone(CardId.MirrorjadeTheIcebladeDragon, faceUp: true) } + }; + + foreach (KeyValuePair>> pair in checkDict) + { + if (mustSummonId > 0 && mustSummonId != pair.Key) continue; + ClientCard currentFusionTarget = canSummonList.FirstOrDefault(c => c != null && c.IsCode(pair.Key)); + if (currentFusionTarget == null) continue; + Func fusionFunc1 = pair.Value[0]; + Func fusionFunc2 = pair.Value[1]; + + if (mustMaterialList != null && mustMaterialList.Count > 0) + { + foreach (ClientCard mustMaterial in mustMaterialList) + { + if (!fusionFunc1(mustMaterial) && !fusionFunc2(mustMaterial)) continue; + foreach (ClientCard anotherMaterial in materialList) + { + if (anotherMaterial == mustMaterial) continue; + bool checkFlag = fusionFunc1(mustMaterial) && fusionFunc2(anotherMaterial); + checkFlag |= fusionFunc2(mustMaterial) && fusionFunc1(anotherMaterial); + extraCheckDict.TryGetValue(pair.Key, out Func extraCheckFunc); + checkFlag &= (extraCheckFunc == null || extraCheckFunc(mustMaterial, anotherMaterial)); + if (checkFlag) + { + fusionTarget = currentFusionTarget; + selectedFusionMaterialList.Add(mustMaterial); + selectedFusionMaterialList.Add(anotherMaterial); + return; + } + } + } + } + else + { + for (int index1 = 0; index1 < materialList.Count - 1; ++index1) + { + ClientCard material1 = materialList[index1]; + if (!fusionFunc1(material1) && !fusionFunc2(material1)) continue; + for (int index2 = index1 + 1; index2 < materialList.Count; ++index2) + { + ClientCard material2 = materialList[index2]; + bool checkFlag = fusionFunc1(material1) && fusionFunc2(material2); + checkFlag |= fusionFunc2(material1) && fusionFunc1(material2); + extraCheckDict.TryGetValue(pair.Key, out Func extraCheckFunc); + checkFlag &= (extraCheckFunc == null || extraCheckFunc(material1, material2)); + if (checkFlag) + { + fusionTarget = currentFusionTarget; + selectedFusionMaterial.Add(material1); + selectedFusionMaterial.Add(material2); + return; + } + } + } + } + } + } + + public bool TriBrigadeMercourierActivate() + { + // negate + if (Card.Location == CardLocation.Hand || Card.Location == CardLocation.MonsterZone) + { + if (CheckWhetherNegated(true, false, CardType.Monster) || !CheckLastChainShouldNegated()) return false; + if (Util.GetLastChainCard().Location == CardLocation.MonsterZone) currentNegateCardList.Add(Util.GetLastChainCard()); + activatedCardIdList.Add(Card.Id); + return true; + } + // search + if (Card.Location == CardLocation.Removed) + { + return false; + } + return false; + } + + public bool TriBrigadeMercourierActivateForSearch() + { + // negate + if (Card.Location == CardLocation.Hand || Card.Location == CardLocation.MonsterZone) + { + return false; + } + // search + if (Card.Location == CardLocation.Removed) + { + if (CheckWhetherNegated(true, false, CardType.Monster)) return false; + activatedCardIdList.Add(Card.Id + 1); + return true; + } + return false; + } + + public bool AshBlossomActivate() + { + if (CheckWhetherNegated() || !CheckLastChainShouldNegated()) return false; + if (Util.GetLastChainCard().IsCode(_CardId.MaxxC)) return false; + if (DefaultAshBlossomAndJoyousSpring()) + { + ClientCard lastChainCard = Util.GetLastChainCard(); + if (lastChainCard.Location == CardLocation.MonsterZone || lastChainCard.Location == CardLocation.SpellZone) currentNegateCardList.Add(Util.GetLastChainCard()); + return true; + } + return false; + } + + public bool MaxxCActivate() + { + if (CheckWhetherNegated(true) || Duel.LastChainPlayer == 0) return false; + return DefaultMaxxC(); + } + + public bool DespianTragedyActivate() + { + // search + if (ActivateDescription != Util.GetStringId(Card.Id, 1)) + { + if (CheckWhetherNegated(true, false, CardType.Monster)) return false; + activatedCardIdList.Add(Card.Id); + return true; + } + // set + else { + if (CheckWhetherNegated(true, false, CardType.Trap)) return false; + Dictionary> checkDict = new Dictionary>{ + {CardId.BrandedFusion, () => BrandedFusionActivateCheck()}, + {CardId.BrandedLost, () => { + if (Duel.Player == 0 && Duel.Phase >= DuelPhase.End) return false; + if (Bot.HasInHandOrInSpellZone(CardId.BrandedFusion) && BrandedFusionActivateCheck()) return true; + if (Bot.HasInHandOrInSpellZone(CardId.BrandedInWhite) && BrandedInWhiteActivateCheck()) return true; + if (Bot.HasInHandOrInSpellZone(CardId.BrandedInRed) && BrandedInRedActivateCheck() != null) return true; + if (!summoned && Bot.HasInHand(CardId.FallenOfAlbaz) && CheckAlbazFusion()) return true; + if ((Bot.HasInMonstersZone(CardId.BlazingCartesiaTheVirtuous) || (!summoned && Bot.HasInHand(CardId.BlazingCartesiaTheVirtuous)))) return true; + return false; + } }, + {CardId.BrandedInHighSpirits, BrandedInHighSpiritsActivateCheck}, + {CardId.BrandedInRed, () => BrandedInRedActivateCheck() != null }, + {CardId.BrandedInWhite, BrandedInWhiteActivateCheck }, + {CardId.BrightestBlazingBrandedKing, () => Bot.GetMonsters().Any(c => c.IsFaceup() && c.IsCode(albazFusionMonster)) }, + {CardId.BrandedOpening, () => Bot.Hand.Count > 2 && !activatedCardIdList.Contains(CardId.BrandedOpening) } + }; + foreach (KeyValuePair> pair in checkDict) + { + ClientCard target = Bot.Graveyard.FirstOrDefault(card => card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + activatedCardIdList.Add(Card.Id); + AI.SelectCard(target); + SelectSTPlace(target, true); + return true; + } + } + } + return false; + } + + public bool DespianTragedySet() + { + if (Bot.Graveyard.Any(c => c != null && c.HasType(CardType.Spell | CardType.Trap) && c.HasSetcode(SetcodeBranded))) + { + summoned = true; + return true; + } + + return false; + } + + public bool NadirServantActivate() + { + if (CheckWhetherNegated(true, true, CardType.Spell) || CheckWhetherWillbeRemoved()) return false; + bool checkResult = NadirServantActivateCheck(null, false, out _); + if (checkResult) + { + SelectSTPlace(Card, true); + return true; + } + return false; + } + + public bool NadirServantActivateCheck(IList cards, bool force, out ClientCard target) + { + Dictionary> checkDict = new Dictionary> + { + {CardId.AlbionTheBrandedDragon, () => !sendToGYThisTurn.Any(c => c.IsCode(CardId.AlbionTheBrandedDragon)) }, + {CardId.DespianLuluwalilith, () => CheckRemainInDeck(CardId.BlazingCartesiaTheVirtuous, CardId.GuidingQuemTheVirtuous) > 0 }, + {CardId.TitanikladTheAshDragon, () => CheckRemainInDeck(CardId.GuidingQuemTheVirtuous) > 0 }, + {CardId.SprindTheIrondashDragon, () => CheckRemainInDeck(CardId.SpringansKitt) > 0 }, + {CardId.RindbrummTheStrikingDragon, () => Bot.Graveyard.Any(c => c != null && c.IsOriginalCode(CardId.FallenOfAlbaz)) }, + {CardId.AlbaLenatusTheAbyssDragon, () => force && CheckRemainInDeck(CardId.FusionDeployment, CardId.BrandedFusion) > 0 }, + {CardId.GranguignolTheDuskDragon, () => force}, + }; + + foreach (KeyValuePair> pair in checkDict) + { + if (cards == null) + { + if (Bot.HasInExtra(pair.Key) && pair.Value()) + { + target = null; + return true; + } + } else + { + ClientCard tg = cards.FirstOrDefault(c => c.IsOriginalCode(pair.Key)); + if (tg != null && pair.Value()) + { + target = tg; + return true; + } + } + } + + target = null; + return false; + } + + public bool FusionDeploymentActivate() + { + if (CheckWhetherNegated(true, true, CardType.Spell)) return false; + if (FusionDeploymentSpSummonTarget() > 0 && !Bot.HasInHand(CardId.BrandedLost)) + { + SelectSTPlace(Card, true); + return true; + } + + return false; + } + + public int FusionDeploymentSpSummonTarget() + { + if (CheckRemainInDeck(CardId.FallenOfAlbaz) > 0 && CheckAlbazFusion(Card) && GetProblematicEnemyMonster(0, false, false, CardType.Monster) != null) + { + return CardId.FallenOfAlbaz; + } + if (CheckRemainInDeck(CardId.BlazingCartesiaTheVirtuous) > 0 && Bot.HasInExtra(CardId.GranguignolTheDuskDragon)) + { + if (Bot.Hand.Any(c => c.IsMonster() && c.HasAttribute(CardAttribute.Light | CardAttribute.Dark)) + || Bot.GetMonsters().Any(c => c.IsMonster() && c.HasAttribute(CardAttribute.Light | CardAttribute.Dark) && !c.IsCode(cannotBeFusionMaterialIdList))) + { + return CardId.BlazingCartesiaTheVirtuous; + } + } + if (CheckRemainInDeck(CardId.FallenOfAlbaz) > 0 && CheckAlbazFusion(Card)) + { + return CardId.FallenOfAlbaz; + } + return 0; + } + + public bool BrandedInWhiteActivate() + { + if (Card.Location == CardLocation.Grave) + { + if (CheckWhetherNegated(true, false, CardType.Spell)) return false; + activatedCardIdList.Add(Card.Id + 1); + SelectSTPlace(Card); + return true; + } else + { + if (_BrandedInWhiteActivateCheck(true)) + { + activatedCardIdList.Add(Card.Id); + SelectSTPlace(Card, true); + return true; + } + } + return false; + } + + public bool BrandedInWhiteActivateCheck() + { + return _BrandedInWhiteActivateCheck(false); + } + + public bool _BrandedInWhiteActivateCheck(bool activate = false) + { + if (CheckWhetherNegated(true, true, CardType.Spell) || activatedCardIdList.Contains(CardId.BrandedInWhite) || nadirActivated) return false; + if (CheckShouldNoMoreSpSummon() && Bot.MonsterZone.Any(c => c != null && c.GetDefensePower() >= 2000)) return false; + if (BrandedInWhiteFusionTarget(Bot.ExtraDeck, out ClientCard _fusionTarget) > 0) + { + if (activate) Logger.DebugWriteLine("White prepare fusion: " + _fusionTarget?.Name); + return true; + } + + return false; + } + + public int BrandedInWhiteFusionTarget(IList cards, out ClientCard target) + { + target = null; + Dictionary> checkDict = new Dictionary> + { + {CardId.MirrorjadeTheIcebladeDragon, () => { + if (Bot.HasInMonstersZone(CardId.MirrorjadeTheIcebladeDragon, faceUp: true) || Bot.HasInSpellZone(CardId.MirrorjadeTheIcebladeDragon, faceUp: true)) return false; + bool albazFlag = Bot.Graveyard.Any(c => c.IsCode(CardId.FallenOfAlbaz)); + albazFlag |= Bot.MonsterZone.Any(c => c != null && c.IsOriginalCode(CardId.FallenOfAlbaz)); + albazFlag |= Bot.Hand.Any(c => c.IsOriginalCode(CardId.FallenOfAlbaz)); + if (!albazFlag) return false; + + bool checkFlag = Bot.Graveyard.Any(c => c != null && !sendToGYThisTurn.Contains(c) && !c.IsCode(cannotBeFusionMaterialIdList) + && c.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link)); + checkFlag |= Bot.MonsterZone.Any(c => c != null && !c.IsCode(cannotBeFusionMaterialIdList) + && (c.IsCode(albazFusionMonster) || c.IsCode(CardId.GranguignolTheDuskDragon))); + return checkFlag; + } }, + {CardId.BorreloadFuriousDragon, () => { + if (Enemy.GetMonsterCount() + Enemy.GetSpellCount() > 0) + { + List darkDragonList = Bot.Hand.Where(c => c != null && c.IsMonster() && c.HasAttribute(CardAttribute.Dark) && c.HasRace(CardRace.Dragon)).ToList(); + darkDragonList.AddRange(Bot.MonsterZone.Where(c => c != null && c.IsMonster() && c.HasAttribute(CardAttribute.Dark) && c.HasRace(CardRace.Dragon) && !c.IsCode(cannotBeFusionMaterialIdList)).ToList()); + List graveDarkDragonList = Bot.Graveyard.Where(c => c.HasRace(CardRace.Dragon) && c.HasAttribute(CardAttribute.Dark) + && !c.IsCode(cannotBeFusionMaterialIdList) && !CheckWhetherShouldKeepInGrave(c) ).ToList(); + + bool hasAlbaz = darkDragonList.Any(c => c.IsCode(CardId.FallenOfAlbaz)) || graveDarkDragonList.Any(c => c.IsCode(CardId.FallenOfAlbaz)); + int darkDragonCount = darkDragonList.Count; + if (hasAlbaz) + { + darkDragonCount += graveDarkDragonList.Count; + } + return darkDragonCount >= 2; + } + return false; + } }, + {CardId.GuardianChimera, () => + { + if (CheckWhetherNegated(true, true, CardType.Monster) || DefaultCheckWhetherCardIdIsNegated(CardId.GuardianChimera)) return false; + int enemyCardCount = Enemy.GetMonsterCount() + Enemy.GetSpellCount(); + if (enemyCardCount == 0) return false; + + return ChimeraFusionMaterialList().Count > 0; + } }, + {CardId.LubellionTheSearingDragon, () => + { + if (activatedCardIdList.Contains(CardId.LubellionTheSearingDragon) + || DefaultCheckWhetherCardIdIsNegated(CardId.LubellionTheSearingDragon) + || CheckWhetherNegated(true, true, CardType.Monster)) + { + return false; + } + List checkMaterialList = new List(Bot.Graveyard.Where(c => c != null && c.IsMonster()).OrderBy(c => c.GetDefensePower())).ToList(); + checkMaterialList.AddRange(Bot.GetMonsters().OrderBy(c => c.GetDefensePower())); + checkMaterialList.AddRange(Bot.Hand); + ClientCard albaz = checkMaterialList.Where(c => c.IsCode(CardId.FallenOfAlbaz)).OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + ClientCard darkMonster = checkMaterialList.Where(c => c != albaz && c.HasAttribute(CardAttribute.Dark)).FirstOrDefault(); + if (albaz == null || darkMonster == null) return false; + if (Bot.Hand.Count(c => c != albaz && c != darkMonster && !c.IsCode(CardId.BrandedInWhite)) == 0) return false; + + return true; + } }, + {CardId.AlbionTheSanctifireDragon, () => + { + List checkMaterialList = new List(Bot.Graveyard.Where(c => c != null && c.IsMonster()).OrderBy(c => c.GetDefensePower())).ToList(); + checkMaterialList.AddRange(Bot.GetMonsters().OrderBy(c => c.GetDefensePower())); + checkMaterialList.AddRange(Bot.Hand); + ClientCard albaz = checkMaterialList.FirstOrDefault(c => c.IsCode(CardId.FallenOfAlbaz)); + ClientCard lightSpellcaster = checkMaterialList.FirstOrDefault(c => c.HasRace(CardRace.SpellCaster) && c.HasAttribute(CardAttribute.Light)); + if (albaz == null || lightSpellcaster == null) return false; + + int remainMonsterCount = Enemy.GetGraveyardMonsters().Count; + remainMonsterCount += Bot.Graveyard.Where(c => c.IsMonster() && c != albaz && c != lightSpellcaster).Count(); + remainMonsterCount += Bot.HasInHand(_CardId.MaxxC) ? 1 : 0; + return remainMonsterCount >= 2; + } }, + {CardId.RindbrummTheStrikingDragon, () => { + if (!Bot.HasInGraveyard(CardId.TriBrigadeMercourier)) return false; + bool albazCheck = Bot.HasInHandOrHasInMonstersZone(CardId.FallenOfAlbaz); + albazCheck |= Bot.HasInGraveyard(CardId.FallenOfAlbaz); + return albazCheck; + } }, + {CardId.DespianQuaeritis, () => + { + bool checkFlag = Enemy.MonsterZone.Any(c => c != null && c.IsFaceup() && c.Attack >= 2500 && !(c.HasType(CardType.Fusion) && c.Level >= 8)); + if (checkFlag) + { + ClientCard despianInGrave = Bot.Graveyard.Where(c => c != null && c.HasSetcode(SetcodeDespain) && !CheckWhetherShouldKeepInGrave(c)) + .OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + if (despianInGrave != null) + { + bool albazCheck = Bot.HasInHandOrHasInMonstersZone(CardId.FallenOfAlbaz); + albazCheck |= Bot.HasInGraveyard(CardId.FallenOfAlbaz); + return albazCheck; + } + List fusionMaterialList = Bot.Hand.Where(c => c.IsMonster()).OrderBy(c => c.GetDefensePower()).ToList(); + fusionMaterialList.AddRange(Bot.MonsterZone.Where(c => c != null && !c.IsCode(cannotBeFusionMaterialIdList)).OrderBy(c => c.GetDefensePower()).ToList()); + ClientCard despian = fusionMaterialList.FirstOrDefault(c => c.HasSetcode(SetcodeDespain)); + if (despian != null) + { + checkFlag = fusionMaterialList.Any(c => c != despian && c.HasAttribute(CardAttribute.Light | CardAttribute.Dark)); + checkFlag |= Bot.HasInGraveyard(CardId.FallenOfAlbaz); + return checkFlag; + } + } + + return false; + } }, + {CardId.TitanikladTheAshDragon, () => + { + List checkMaterialList = new List(Bot.Graveyard.Where(c => c != null && c.IsMonster()).OrderBy(c => c.GetDefensePower())).ToList(); + checkMaterialList.AddRange(Bot.GetMonsters().OrderBy(c => c.GetDefensePower())); + checkMaterialList.AddRange(Bot.Hand); + ClientCard albaz = checkMaterialList.Where(c => c.IsCode(CardId.FallenOfAlbaz)).OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + + foreach (ClientCard material in checkMaterialList) + { + if (material != albaz && material.IsMonster() && material.Attack >= 2500 && !material.IsCode(cannotBeFusionMaterialIdList) && !Util.IsTurn1OrMain2()) + { + bool checkFlag = Enemy.GetMonsterCount() == 0 && !CheckWhetherShouldKeepInGrave(material) && (material.IsFacedown() || material.Location != CardLocation.MonsterZone); + + int expectedAttack = 2900 + material.Level * 100; + int botBestPower = Util.GetBestPower(Bot); + int beforeBetterCount = Enemy.MonsterZone.Count(c => c != null && c.GetDefensePower() >= botBestPower); + int afterBetterCount = Enemy.MonsterZone.Count(c => c != null && c.GetDefensePower() >= expectedAttack); + checkFlag |= afterBetterCount < beforeBetterCount; + + return checkFlag; + } + } + return false; + } }, + {CardId.AlbaLenatusTheAbyssDragon, () => + { + if (Util.GetOneEnemyBetterThanMyBest() == null && Duel.MainPhase.CanBattlePhase) + { + ClientCard albaz = Bot.Graveyard.FirstOrDefault(c => c != null && c.IsOriginalCode(CardId.FallenOfAlbaz)); + if (albaz == null) + { + albaz = Bot.Graveyard.FirstOrDefault(c => c != null && c.IsCode(CardId.FallenOfAlbaz)); + } + if (albaz == null) return false; + foreach (ClientCard material in Bot.Graveyard) + { + if (material != null && material != albaz && material.IsMonster() && material.HasRace(CardRace.Dragon) && !material.IsCode(cannotBeFusionMaterialIdList)) + { + return true; + } + } + } + return false; + } } + }; + + foreach (KeyValuePair> pair in checkDict) + { + target = cards.FirstOrDefault(card => card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + return pair.Key; + } + } + + target = null; + return 0; + } + + public List ChimeraFusionMaterialList(bool dragonCheck = true) + { + int enemyCardCount = Enemy.GetMonsterCount() + Enemy.GetSpellCount(); + + List fieldMonsterList = Bot.MonsterZone.Where(c => c != null && c.GetDefensePower() <= 2500 && !c.IsCode(cannotBeFusionMaterialIdList)) + .OrderBy(c => c.GetDefensePower()).ToList(); + List handMonsterList = Bot.Hand.Where(c => c.IsMonster()) + .OrderBy(c => c.GetDefensePower()).ToList(); + // 2 monsters on field + 1 monster in hand + if (enemyCardCount >= 2 && fieldMonsterList.Count >= 2) + { + if (fieldMonsterList.Count < 2 || handMonsterList.Count < 1) return new List() ; + foreach (ClientCard handMonster in handMonsterList) + { + for (int fieldIndex1 = 0; fieldIndex1 < fieldMonsterList.Count - 1; ++fieldIndex1) + { + ClientCard fieldMonster1 = fieldMonsterList[fieldIndex1]; + if (fieldMonster1.IsCode(handMonster.Id) || handMonster.IsCode(fieldMonster1.Id)) continue; + for (int fieldIndex2 = fieldIndex1 + 1; fieldIndex2 < fieldMonsterList.Count; ++fieldIndex2) + { + ClientCard fieldMonster2 = fieldMonsterList[fieldIndex2]; + if (fieldMonster2.IsCode(handMonster.Id) || handMonster.IsCode(fieldMonster2.Id)) continue; + if (fieldMonster2.IsCode(fieldMonster1.Id) || fieldMonster1.IsCode(fieldMonster2.Id)) continue; + + List materialList = new List { handMonster, fieldMonster1, fieldMonster2 }; + bool checkFlag = dragonCheck && materialList.Any(c => c.HasRace(CardRace.Dragon)); + if (checkFlag) + { + return materialList; + } + } + } + } + } + // 1 monster on field + 2 monsters in hand + if (enemyCardCount == 1 || fieldMonsterList.Count == 1) + { + if (fieldMonsterList.Count < 1 || handMonsterList.Count < 2) return new List(); + foreach (ClientCard fieldMonster in fieldMonsterList) + { + for (int handIndex1 = 0; handIndex1 < handMonsterList.Count - 1; ++handIndex1) + { + ClientCard handMonster1 = handMonsterList[handIndex1]; + if (handMonster1.IsCode(fieldMonster.Id) || fieldMonster.IsCode(handMonster1.Id)) continue; + for (int handIndex2 = handIndex1 + 1; handIndex2 < handMonsterList.Count; ++handIndex2) + { + ClientCard handMonster2 = handMonsterList[handIndex2]; + if (handMonster2.IsCode(fieldMonster.Id) || fieldMonster.IsCode(handMonster2.Id)) continue; + if (handMonster2.IsCode(handMonster1.Id) || handMonster1.IsCode(handMonster2.Id)) continue; + + List materialList = new List { fieldMonster, handMonster1, handMonster2 }; + bool checkFlag = dragonCheck && materialList.Any(c => c.HasRace(CardRace.Dragon)); + if (checkFlag) + { + return materialList; + } + } + } + } + } + + return new List(); + } + + public bool BrandedFusionActivate() + { + if (BrandedFusionActivateCheck()) + { + SelectSTPlace(Card, true); + return true; + } + return false; + } + + public bool BrandedFusionActivateCheck(bool endPhaseCheck = true) + { + if (CheckWhetherNegated(true, true, CardType.Spell) || activatedCardIdList.Contains(CardId.BrandedFusion)) return false; + if (!Bot.HasInHandOrHasInMonstersZone(CardId.FallenOfAlbaz) && CheckRemainInDeck(CardId.FallenOfAlbaz) == 0) return false; + if (endPhaseCheck && Duel.Phase >= DuelPhase.End) return false; + return true; + } + + public bool GoldSarcophagusActivate() + { + if (CheckWhetherNegated(true, true, CardType.Spell)) return false; + if (GoldSarcophagusTarget(null, out _) > 0) + { + SelectSTPlace(Card, true); + return true; + } + return false; + } + + public int GoldSarcophagusTarget(IList cards, out ClientCard target) + { + Dictionary> checkDict = new Dictionary> + { + {CardId.DespianTragedy, () => !activatedCardIdList.Contains(CardId.DespianTragedy) && !DefaultCheckWhetherCardIdIsNegated(CardId.DespianTragedy) }, + {CardId.TriBrigadeMercourier, () => !activatedCardIdList.Contains(CardId.TriBrigadeMercourier + 1) && !DefaultCheckWhetherCardIdIsNegated(CardId.TriBrigadeMercourier) } + }; + foreach (KeyValuePair> pair in checkDict) + { + int cardId = pair.Key; + if (pair.Value()) + { + if (cards != null) + { + target = cards.FirstOrDefault(card => card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + return cardId; + } + } + else if (CheckRemainInDeck(cardId) > 0) + { + target = null; + return cardId; + } + } + } + + target = null; + return 0; + } + + public bool FoolishBurialActivate() + { + if (CheckWhetherNegated(true, true, CardType.Spell) || CheckWhetherWillbeRemoved()) return false; + if (FoolishBurialTarget(null, out _) > 0) + { + SelectSTPlace(Card, true); + return true; + } + return false; + } + + public int FoolishBurialTarget(IList cards, out ClientCard target) + { + // tragedy + if (!activatedCardIdList.Contains(CardId.DespianTragedy) && !DefaultCheckWhetherCardIdIsNegated(CardId.DespianTragedy)) + { + if (cards != null) + { + target = cards.FirstOrDefault(c => c.IsCode(CardId.DespianTragedy)); + if (target != null) + { + return CardId.DespianTragedy; + } + } else + { + if (CheckRemainInDeck(CardId.DespianTragedy) > 0) + { + target = null; + return CardId.DespianTragedy; + } + } + } + + // send to GY check + bool sendToGYFlag = CheckRemainInDeck(CardId.BrandedRetribution) > 0; + sendToGYFlag |= Bot.HasInGraveyard(CardId.BrandedRetribution) && CheckRemainInDeck(CardId.BrandedFusion) > 0; + if (sendToGYFlag) + { + Dictionary> checkDict = new Dictionary> + { + {CardId.BystialSaronir, () => !activatedCardIdList.Contains(CardId.BystialSaronir + 1) && !DefaultCheckWhetherCardIdIsNegated(CardId.BystialSaronir) }, + {CardId.AlbionTheShroudedDragon, () => !activatedCardIdList.Contains(CardId.AlbionTheShroudedDragon) && !DefaultCheckWhetherCardIdIsNegated(CardId.AlbionTheShroudedDragon) } + }; + + foreach (KeyValuePair> pair in checkDict) + { + int cardId = pair.Key; + if (pair.Value()) + { + if (cards != null) + { + target = cards.FirstOrDefault(card => card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + return cardId; + } + } else if (CheckRemainInDeck(cardId) > 0) + { + target = null; + return cardId; + } + } + } + } + + // albaz + if (!Bot.HasInGraveyard(CardId.FallenOfAlbaz)) + { + bool albazCheckFlag = Bot.HasInHand(new List { CardId.BrandedInRed, CardId.BrandedInWhite }); + albazCheckFlag |= Bot.HasInHand(CardId.BlazingCartesiaTheVirtuous) && Bot.MonsterZone.Count(c => c != null && c.Sequence < 5) < 5; + if (albazCheckFlag) + { + int albazCountCheck = Bot.HasInHandOrInSpellZone(CardId.BrandedFusion) ? 2 : 1; + if (cards != null) + { + List albazList = cards.Where(c => c.IsCode(CardId.FallenOfAlbaz)).ToList(); + if (albazList.Count >= albazCountCheck) + { + target = albazList.First(); + return CardId.FallenOfAlbaz; + } + } else + { + if (CheckRemainInDeck(CardId.FallenOfAlbaz) >= albazCountCheck) + { + target = null; + return CardId.FallenOfAlbaz; + } + } + } + } + + target = null; + return 0; + } + + public bool CalledbytheGraveActivate() + { + if (CheckWhetherNegated() || !CheckLastChainShouldNegated()) return false; + if (CheckAtAdvantage() && Duel.LastChainPlayer == 1 && Util.GetLastChainCard().IsCode(_CardId.MaxxC)) + { + return false; + } + if (Duel.LastChainPlayer == 1) + { + // negate + if (Util.GetLastChainCard().IsMonster()) + { + int code = Util.GetLastChainCard().GetOriginCode(); + if (code == 0) return false; + if (DefaultCheckWhetherCardIdIsNegated(code)) return false; + if (Util.GetLastChainCard().IsCode(_CardId.MaxxC) && CheckAtAdvantage()) + { + return false; + } + ClientCard graveTarget = Enemy.Graveyard.GetFirstMatchingCard(card => card.IsMonster() && card.GetOriginCode() == code); + if (graveTarget != null) + { + if (!(Card.Location == CardLocation.SpellZone)) + { + SelectSTPlace(null, true); + } + AI.SelectCard(graveTarget); + currentDestroyCardList.Add(graveTarget); + return true; + } + } + + // banish target + foreach (ClientCard graveCard in Enemy.Graveyard) + { + if (Duel.ChainTargets.Contains(graveCard) && graveCard.IsMonster()) + { + if (!(Card.Location == CardLocation.SpellZone)) + { + SelectSTPlace(null, true); + } + int code = graveCard.Id; + AI.SelectCard(graveCard); + currentDestroyCardList.Add(graveCard); + return true; + } + } + + // become targets + if (Duel.ChainTargets.Contains(Card)) + { + List enemyMonsters = Enemy.Graveyard.GetMatchingCards(card => card.IsMonster()).ToList(); + if (enemyMonsters.Count > 0) + { + enemyMonsters.Sort(CardContainer.CompareCardAttack); + enemyMonsters.Reverse(); + int code = enemyMonsters[0].Id; + AI.SelectCard(code); + currentDestroyCardList.Add(enemyMonsters[0]); + return true; + } + } + } + + // avoid danger monster in grave + if (Duel.LastChainPlayer == 1) return false; + List targets = GetDangerousCardinEnemyGrave(true); + if (targets.Count > 0) + { + int code = targets[0].Id; + if (!(Card.Location == CardLocation.SpellZone)) + { + SelectSTPlace(null, true); + } + AI.SelectCard(code); + currentDestroyCardList.Add(targets[0]); + return true; + } + + return false; + } + + public bool BrandedInHighSpiritsActivate() + { + if (Card.Location == CardLocation.Grave) + { + if (CheckWhetherNegated(true, false, CardType.Spell)) return false; + activatedCardIdList.Add(Card.Id); + return true; + } else + { + if (BrandedInHighSpiritsActivateCheck()) + { + activatedCardIdList.Add(Card.Id); + SelectSTPlace(Card, true); + return true; + } + } + return false; + } + + public bool BrandedInHighSpiritsActivateCheck() + { + bool lubellionCheck = Bot.HasInHand(CardId.TheBystialLubellion) && CheckRemainInDeck(CardId.BystialSaronir) > 0 && !activatedCardIdList.Contains(CardId.TheBystialLubellion) + && Duel.Player == 0 && (Duel.Phase <= DuelPhase.Main1 || Duel.Phase == DuelPhase.Main2) && !CheckWhetherWillbeRemoved(); + + if (CheckWhetherNegated(true, true, CardType.Spell) || activatedCardIdList.Contains(CardId.BrandedInHighSpirits) || CheckWhetherWillbeRemoved()) return false; + Dictionary> checkDict = new Dictionary> + { + {CardId.AlbionTheBrandedDragon, () => !sendToGYThisTurn.Any(c => c.IsCode(CardId.AlbionTheBrandedDragon)) && !lubellionCheck + && Bot.Hand.Any(c => BrandedInHighSpiritDiscardDragonCheck(c) ) }, + {CardId.TitanikladTheAshDragon, () => !sendToGYThisTurn.Any(c => c.IsCode(CardId.TitanikladTheAshDragon)) && !lubellionCheck + && Bot.Hand.Any(c => BrandedInHighSpiritDiscardDragonCheck(c) ) + && CheckRemainInDeck(CardId.GuidingQuemTheVirtuous, CardId.FallenOfAlbaz) > 0}, + {CardId.GranguignolTheDuskDragon, () => Bot.Hand.Any(c => c.HasRace(CardRace.SpellCaster) && !(CheckWhetherCanSummon() && c.IsOriginalCode(CardId.GuidingQuemTheVirtuous))) }, + {CardId.RindbrummTheStrikingDragon, () => Bot.Hand.Any(c => c.HasRace(CardRace.WindBeast) + && (!c.IsCode(CardId.TriBrigadeMercourier) || !Bot.MonsterZone.Any(c2 => c2 != null && c2.IsFaceup() && c2.IsCode(albazFusionMonster)))) } + }; + + foreach (KeyValuePair> pair in checkDict) + { + if (Bot.HasInExtra(pair.Key) && pair.Value()) + { + return true; + } + } + return false; + } + + public bool BrandedInHighSpiritDiscardDragonCheck(ClientCard card) + { + if (!card.HasRace(CardRace.Dragon)) return false; + if (Duel.Player == 0 && (Duel.Phase <= DuelPhase.Main1 || Duel.Phase == DuelPhase.Main2)) + { + if (card.IsOriginalCode(CardId.AlbionTheShroudedDragon) && !activatedCardIdList.Contains(CardId.AlbionTheShroudedDragon)) return false; + if (card.IsOriginalCode(CardId.TheBystialLubellion) && !activatedCardIdList.Contains(CardId.TheBystialLubellion) && CheckRemainInDeck(CardId.BystialSaronir) > 0) return false; + } + + return true; + } + + public bool BrandedOpeningActivate() + { + if (CheckWhetherNegated(true, true, CardType.Spell)) return false; + if (Duel.Player == 0) + { + if (Bot.HasInHand(CardId.AlbionTheShroudedDragon) && !CheckWhetherWillbeRemoved() && !activatedCardIdList.Contains(CardId.AlbionTheShroudedDragon)) return false; + bool canCallCartesia = Bot.HasInHand(CardId.BlazingCartesiaTheVirtuous) && !summoned; + canCallCartesia |= !activatedCardIdList.Contains(CardId.FusionDeployment) && Bot.HasInHandOrInSpellZone(CardId.FusionDeployment) + && !CheckShouldNoMoreSpSummon() && Bot.HasInExtra(CardId.GranguignolTheDuskDragon) && CheckRemainInDeck(CardId.BlazingCartesiaTheVirtuous) > 0; + if (canCallCartesia) return false; + } + bool goal = CheckRemainInDeck(CardId.AluberTheJesterOfDespia) > 0 && !activatedCardIdList.Contains(CardId.AluberTheJesterOfDespia) && !enemyActivateLockBird; + goal |= CheckRemainInDeck(CardId.GuidingQuemTheVirtuous) > 0; + if (goal) + { + SelectSTPlace(Card, true); + activatedCardIdList.Add(Card.Id); + return true; + } + return false; + } + + public bool CrossoutDesignatorActivate() + { + if (CheckWhetherNegated() || !CheckLastChainShouldNegated()) return false; + // negate + if (Duel.LastChainPlayer == 1 && Util.GetLastChainCard() != null) + { + int code = Util.GetLastChainCard().Id; + int alias = Util.GetLastChainCard().Alias; + if (alias != 0 && alias - code < 10) code = alias; + if (code == 0) return false; + if (DefaultCheckWhetherCardIdIsNegated(code)) return false; + if (CheckRemainInDeck(code) > 0) + { + if (!(Card.Location == CardLocation.SpellZone)) + { + SelectSTPlace(null, true); + } + AI.SelectAnnounceID(code); + return true; + } + } + return false; + } + + public bool BrandedInRedActivate() + { + ClientCard targetCard = BrandedInRedActivateCheck(true); + if (targetCard != null) + { + AI.SelectCard(targetCard); + SelectSTPlace(Card, true); + return true; + } + return false; + } + + public ClientCard BrandedInRedActivateCheck(bool updateMaterialList = false) + { + if (CheckWhetherNegated(true, true, CardType.Spell) || activatedCardIdList.Contains(CardId.BrandedInRed)) return null; + if (Duel.CurrentChain.Any(c => c != null && c.Controller == 0 && c.IsCode(CardId.BlazingCartesiaTheVirtuous))) return null; + if (Duel.CurrentChain.Any(c => c != null && c.Controller == 0 && c.IsCode(CardId.AlbionTheBrandedDragon)) + && !Util.ChainContainPlayer(1)) return null; + if (nadirActivated) return null; + + List materialList = Bot.MonsterZone.Where(c => c != null && c.Attack <= 2500 && !c.IsCode(cannotBeFusionMaterialIdList)).ToList(); + materialList.AddRange(Bot.Hand.Where(c => c.IsMonster() + && !(CheckWhetherCanSummon() && + ((!activatedCardIdList.Contains(CardId.AluberTheJesterOfDespia) && c.IsCode(CardId.AluberTheJesterOfDespia)) + || (!activatedCardIdList.Contains(CardId.SpringansKitt) && c.IsCode(CardId.SpringansKitt))) + ) + ) + ); + + List graveTargetList = Bot.Graveyard.Where(c => c != null && c.IsMonster() && !c.HasType(CardType.Fusion | CardType.Synchro) + && (c.IsCode(CardId.FallenOfAlbaz) || c.HasSetcode(SetcodeDespain))).ToList(); + + // select targeted monster + if (Duel.LastChainPlayer == 1) + { + // escape grave monster + List targetedList = Duel.LastChainTargets.Where(c => c != null && c.Location == CardLocation.Grave && c.Controller == 0 + && !c.HasType(CardType.Fusion | CardType.Synchro) && (c.IsCode(CardId.FallenOfAlbaz) || c.HasSetcode(SetcodeDespain))).ToList(); + + if (targetedList.Count > 0) + { + foreach (ClientCard target in targetedList) + { + List newMaterialList = new List(materialList) { target }; + BrandedInRedFusionCheck(Bot.ExtraDeck, 0, newMaterialList, new List { target }, out ClientCard _fusionTarget, out _); + if (_fusionTarget != null) + { + if (updateMaterialList) Logger.DebugWriteLine("Red prepare fusion 1: " + _fusionTarget.Name); + return target; + } + } + } + + // escape target + ClientCard lastCahinCard = Util.GetLastChainCard(); + if (lastCahinCard != null) + { + List chainTargetList = Duel.LastChainTargets.Where(c => c.Controller == 0 && c.Location == CardLocation.MonsterZone + && (!c.IsCode(cannotBeFusionMaterialIdList) || c.Attack <= 2500)).ToList(); + if (chainTargetList.Count > 0) + { + if (lastCahinCard.IsCode(targetNegateIdList)) + { + chainTargetList = chainTargetList.Where(c => c.Attack <= 2500 && !c.IsCode(CardId.AlbionTheBrandedDragon)).ToList(); + } + + foreach (ClientCard target in graveTargetList) + { + List newMaterialList = new List(materialList) { target }; + BrandedInRedFusionCheck(Bot.ExtraDeck, 0, newMaterialList, chainTargetList, + out ClientCard _fusionTarget, out List usedMaterialList); + + if (_fusionTarget != null) + { + if (updateMaterialList) + { + Logger.DebugWriteLine("Red prepare fusion 2: " + _fusionTarget.Name); + brandedInRedMaterialList.AddRange(usedMaterialList.Intersect(chainTargetList)); + } + return target; + } + } + } + } + } + + bool shouldSummonFirst = Duel.Player == 0 && (Duel.Phase <= DuelPhase.Main1 || Duel.Phase == DuelPhase.Main2) && !summoned + && (Bot.HasInHand(new int[] { CardId.AluberTheJesterOfDespia, CardId.GuidingQuemTheVirtuous, CardId.SpringansKitt }) + || Bot.HasInHand(CardId.FallenOfAlbaz) && CheckAlbazFusion(Card)); + bool idleFlag = Duel.Player == 1 || CurrentTiming == -1; + + if (shouldSummonFirst || !idleFlag) return null; + + // for fusion searing dragon + if (!Bot.MonsterZone.Any(c => c != null && c.HasType(CardType.Fusion)) && Duel.LastChainPlayer != 0 + && !CheckWhetherNegated(true, true, CardType.Monster) && !activatedCardIdList.Contains(CardId.LubellionTheSearingDragon)) + { + foreach (ClientCard target in graveTargetList) + { + List newMaterialList = new List(materialList) { target }; + BrandedInRedFusionCheck(Bot.ExtraDeck, CardId.LubellionTheSearingDragon, newMaterialList, new List { target }, out ClientCard _fusionTarget, out _); + if (_fusionTarget != null) + { + return target; + } + } + } + + // remove cards + List problemCardList = GetProblematicEnemyCardList(false, false, CardType.Monster); + if (problemCardList.Count > 0 || (Duel.Phase == DuelPhase.End && Duel.Player == 1)) + { + if (!enemyActivateLockBird) + { + foreach (ClientCard target in graveTargetList) + { + List newMaterialList = new List(materialList) { target }; + BrandedInRedFusionCheck(Bot.ExtraDeck, CardId.GuardianChimera, newMaterialList, new List { target }, out ClientCard _fusionTarget, out _); + if (_fusionTarget != null) + { + if (updateMaterialList) Logger.DebugWriteLine("Red prepare fusion 3: " + _fusionTarget.Name); + return target; + } + } + } + + foreach (ClientCard target in graveTargetList) + { + List newMaterialList = new List(materialList) { target }; + BrandedInRedFusionCheck(Bot.ExtraDeck, CardId.BorreloadFuriousDragon, newMaterialList, new List { target }, out ClientCard _fusionTarget, out _); + if (_fusionTarget != null) + { + if (updateMaterialList) Logger.DebugWriteLine("Red prepare fusion 4: " + _fusionTarget.Name); + return target; + } + } + } + + return null; + } + + public void BrandedInRedFusionCheck( + IList canSummonList, int mustSummonId, + List materialList, List mustMaterialList, + out ClientCard fusionTarget, out List selectedFusionMaterialList) + { + fusionTarget = null; + selectedFusionMaterialList = new List(); + + // fusion id + // material condition + // extra check function + // search material function + List>, + Func, bool>, + Func, List, List>, Func, bool>, List> + >> checkTupleList = new List>, Func, bool>, + Func, List, List>, Func, bool>, List> + >> + { + new Tuple>, Func, bool>, + Func, List, List>, Func, bool>, List>>( + CardId.MirrorjadeTheIcebladeDragon, new List> + { + (c) => c.IsCode(CardId.FallenOfAlbaz), + (c) => !c.IsCode(cannotBeFusionMaterialIdList) && c.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link) + }, + (l) => !Bot.HasInMonstersZone(CardId.MirrorjadeTheIcebladeDragon, faceUp: true) && !Bot.HasInSpellZone(CardId.MirrorjadeTheIcebladeDragon, faceUp: true), + BrandedInRedUsing2SubFunc + ), + new Tuple>, Func, bool>, + Func, List, List>, Func, bool>, List>>( + CardId.LubellionTheSearingDragon, new List> + { + (c) => c.IsCode(CardId.FallenOfAlbaz), + (c) => !c.IsCode(cannotBeFusionMaterialIdList) && c.HasAttribute(CardAttribute.Dark) + }, + (l) => !Bot.HasInMonstersZone(CardId.MirrorjadeTheIcebladeDragon, faceUp: true) && !Bot.HasInSpellZone(CardId.MirrorjadeTheIcebladeDragon, faceUp: true) + && Bot.Hand.Count(c => !l.Contains(c)) > 0 && !activatedCardIdList.Contains(CardId.LubellionTheSearingDragon), + BrandedInRedUsing2SubFunc + ), + new Tuple>, Func, bool>, + Func, List, List>, Func, bool>, List>>( + CardId.GuardianChimera, + null, + null, + BrandedInRedForChimeraFunc + ), + new Tuple>, Func, bool>, + Func, List, List>, Func, bool>, List>>( + CardId.DespianQuaeritis, new List> + { + (c) => c.HasSetcode(SetcodeDespain), + (c) => !c.IsCode(cannotBeFusionMaterialIdList) && c.HasAttribute(CardAttribute.Light | CardAttribute.Dark) + }, + null, + BrandedInRedUsing2SubFunc + ), + new Tuple>, Func, bool>, + Func, List, List>, Func, bool>, List>>( + CardId.BorreloadFuriousDragon, new List> + { + (c) => !c.IsCode(cannotBeFusionMaterialIdList) && c.HasAttribute(CardAttribute.Dark) && c.HasRace(CardRace.Dragon), + (c) => !c.IsCode(cannotBeFusionMaterialIdList) && c.HasAttribute(CardAttribute.Dark) && c.HasRace(CardRace.Dragon) + }, + null, + BrandedInRedUsing2SubFunc + ), + new Tuple>, Func, bool>, + Func, List, List>, Func, bool>, List>>( + CardId.AlbionTheSanctifireDragon, new List> + { + (c) => c.IsCode(CardId.FallenOfAlbaz), + (c) => !c.IsCode(cannotBeFusionMaterialIdList) && c.HasAttribute(CardAttribute.Light) && c.HasRace(CardRace.SpellCaster) + }, + (l) => Enemy.Graveyard.Count(c => c != null && c.IsMonster() && c.IsCanRevive()) + + Bot.Graveyard.Count(c => c != null && !l.Contains(c)) >= 2, + BrandedInRedUsing2SubFunc + ), + }; + + foreach (Tuple>, Func, bool>, + Func, List, List>, Func, bool>, List>> tuple in checkTupleList) + { + if (mustSummonId > 0 && mustSummonId != tuple.Item1) continue; + ClientCard currentFusionTarget = canSummonList.FirstOrDefault(c => c != null && c.IsCode(tuple.Item1)); + if (currentFusionTarget == null) continue; + Func, List, List>, Func, bool>, List> materialFunc = tuple.Item4; + + List currentMaterialList = materialFunc(materialList, mustMaterialList, tuple.Item2, tuple.Item3); + if (currentMaterialList.Count > 0) + { + fusionTarget = currentFusionTarget; + selectedFusionMaterialList = currentMaterialList; + return; + } + } + } + + public List BrandedInRedUsing2SubFunc(List materialList, List mustMaterialList, + List> checkFuncList, Func, bool> extraCheckFunc) + { + List selectedFusionMaterialList = new List(); + + Func fusionFunc1 = checkFuncList[0]; + Func fusionFunc2 = checkFuncList[1]; + + if (mustMaterialList != null && mustMaterialList.Count > 0) + { + foreach (ClientCard mustMaterial in mustMaterialList) + { + if (!fusionFunc1(mustMaterial) && !fusionFunc2(mustMaterial)) continue; + foreach (ClientCard anotherMaterial in materialList) + { + if (anotherMaterial == mustMaterial) continue; + bool checkFlag = fusionFunc1(mustMaterial) && fusionFunc2(anotherMaterial); + checkFlag |= fusionFunc2(mustMaterial) && fusionFunc1(anotherMaterial); + checkFlag &= (extraCheckFunc == null || extraCheckFunc(new List { mustMaterial, anotherMaterial })); + if (checkFlag) + { + selectedFusionMaterialList.Add(mustMaterial); + selectedFusionMaterialList.Add(anotherMaterial); + return selectedFusionMaterialList; + } + } + } + } + else + { + for (int index1 = 0; index1 < materialList.Count - 1; ++index1) + { + ClientCard material1 = materialList[index1]; + if (!fusionFunc1(material1) && !fusionFunc2(material1)) continue; + for (int index2 = index1 + 1; index2 < materialList.Count; ++index2) + { + ClientCard material2 = materialList[index2]; + bool checkFlag = fusionFunc1(material1) && fusionFunc2(material2); + checkFlag |= fusionFunc2(material1) && fusionFunc1(material2); + checkFlag &= (extraCheckFunc == null || extraCheckFunc(new List { material1, material2 })); + if (checkFlag) + { + selectedFusionMaterial.Add(material1); + selectedFusionMaterial.Add(material2); + return selectedFusionMaterialList; + } + } + } + } + + return selectedFusionMaterial; + } + + public List BrandedInRedForChimeraFunc(List materialList, List mustMaterialList, + List> checkFuncList, Func, bool> extraCheckFunc) + { + List selectedFusionMaterialList = new List(); + + int enemyCardCount = Enemy.MonsterZone.Count(c => c != null); + enemyCardCount += Enemy.SpellZone.Count(c => c != null && c.Type != (int)CardType.Spell && c.Type != (int)CardType.Trap); + if (enemyCardCount == 0 || CheckWhetherNegated(true, true, CardType.Monster)) + { + return selectedFusionMaterialList; + } + + List fieldMaterialList = materialList.Where(c => c.Location == CardLocation.MonsterZone).OrderBy(c => c.Attack).ToList(); + List handMaterialList = materialList.Where(c => c.Location == CardLocation.Hand || c.Location == CardLocation.Grave).OrderBy(c => c.Attack).ToList(); + + // 2 field monster + 1 hand monster + if (enemyCardCount >= 2) + { + foreach (ClientCard handMonster in handMaterialList) + { + for (int fieldIndex1 = 0; fieldIndex1 < fieldMaterialList.Count - 1; ++fieldIndex1) + { + ClientCard fieldMonster1 = fieldMaterialList[fieldIndex1]; + if (fieldMonster1.IsCode(handMonster.Id) || handMonster.IsCode(fieldMonster1.Id)) continue; + for (int fieldIndex2 = fieldIndex1 + 1; fieldIndex2 < fieldMaterialList.Count; ++fieldIndex2) + { + ClientCard fieldMonster2 = fieldMaterialList[fieldIndex2]; + if (fieldMonster2.IsCode(fieldMonster1.Id) || fieldMonster1.IsCode(fieldMonster2.Id)) continue; + if (fieldMonster2.IsCode(handMonster.Id) || handMonster.IsCode(fieldMonster2.Id)) continue; + + return new List { handMonster, fieldMonster1, fieldMonster2 }; + } + } + } + } + + // 1 field monster + 2 hand monster + foreach (ClientCard fieldMonster in fieldMaterialList) + { + for (int handIndex1 = 0; handIndex1 < handMaterialList.Count - 1; ++ handIndex1) + { + ClientCard handMonster1 = handMaterialList[handIndex1]; + if (handMonster1.IsCode(fieldMonster.Id) || fieldMonster.IsCode(handMonster1.Id)) continue; + for (int handIndex2 = handIndex1 + 1; handIndex2 < handMaterialList.Count; ++handIndex2) + { + ClientCard handMonster2 = handMaterialList[handIndex2]; + if (handMonster2.IsCode(handMonster1.Id) || handMonster1.IsCode(handMonster2.Id)) continue; + if (handMonster2.IsCode(fieldMonster.Id) || fieldMonster.IsCode(handMonster2.Id)) continue; + + return new List { fieldMonster, handMonster1, handMonster2 }; + } + } + } + + return selectedFusionMaterialList; + } + + public bool BrandedLostActivate() + { + // search + if (Card.Location == CardLocation.SpellZone && Card.IsFaceup()) + { + return true; + } + + return false; + } + + public bool BrandedLostCardActivate() + { + // search + if (Card.Location == CardLocation.SpellZone && Card.IsFaceup()) return false; + + // activate + if (CheckWhetherNegated(true, true, CardType.Spell)) return false; + if (!summoned && Bot.HasInHand(CardId.FallenOfAlbaz) && CheckAlbazFusion() && Bot.Hand.Count < 3) return false; + SelectSTPlace(Card, true); + return true; + } + + public bool InfiniteImpermanenceActivate() + { + if (CheckWhetherNegated()) return false; + + ClientCard LastChainCard = Util.GetLastChainCard(); + + // negate spells + if (Card.Location == CardLocation.SpellZone) + { + int this_seq = -1; + int that_seq = -1; + for (int i = 0; i < 5; ++i) + { + if (Bot.SpellZone[i] == Card) this_seq = i; + if (LastChainCard != null + && LastChainCard.Controller == 1 && LastChainCard.Location == CardLocation.SpellZone && Enemy.SpellZone[i] == LastChainCard) that_seq = i; + else if (Duel.Player == 0 && Util.GetProblematicEnemySpell() != null + && Enemy.SpellZone[i] != null && Enemy.SpellZone[i].IsFloodgate()) that_seq = i; + } + if ((this_seq * that_seq >= 0 && this_seq + that_seq == 4) + || Util.IsChainTarget(Card) + || (LastChainCard != null && LastChainCard.Controller == 1 && LastChainCard.IsCode(_CardId.HarpiesFeatherDuster))) + { + ClientCard target = GetProblematicEnemyMonster(canBeTarget: true); + if (target != null) + { + AI.SelectCard(target); + } + else + { + AI.SelectCard(Enemy.GetMonsters()); + } + infiniteImpermanenceList.Add(this_seq); + return true; + } + } + + // negate monster + List shouldNegateList = GetMonsterListForTargetNegate(true, CardType.Trap); + if (shouldNegateList.Count > 0) + { + ClientCard negateTarget = shouldNegateList[0]; + currentNegateCardList.Add(negateTarget); + + if (Card.Location == CardLocation.SpellZone) + { + for (int i = 0; i < 5; ++i) + { + if (Bot.SpellZone[i] == Card) + { + infiniteImpermanenceList.Add(i); + break; + } + } + } + if (Card.Location == CardLocation.Hand) + { + SelectSTPlace(Card, true); + } + AI.SelectCard(negateTarget); + return true; + } + + return false; + } + + public bool BrightestBlazingBrandedKingActivate() + { + if (Card.Location == CardLocation.Grave) + { + if (CheckWhetherNegated(true, false, CardType.Trap)) return false; + activatedCardIdList.Add(Card.Id); + return true; + } + if (Card.Location == CardLocation.SpellZone) + { + if (Duel.CurrentChain.Any(c => c.Controller == 0 && c.IsFaceup() && (c.Location == CardLocation.MonsterZone || c.Location == CardLocation.SpellZone) + && !c.IsCode(albazFusionMonster))) + { + return false; + } + if (Duel.CurrentChain.Any(c => c.Controller == 1 && c.IsFaceup() && !currentNegateCardList.Contains(c) && !currentDestroyCardList.Contains(c) + && (c.Location == CardLocation.MonsterZone || c.Location == CardLocation.SpellZone))) + { + currentNegateCardList.AddRange(Enemy.MonsterZone.Where(c => c != null && c.IsFaceup())); + currentNegateCardList.AddRange(Enemy.SpellZone.Where(c => c != null && c.IsFaceup())); + activatedCardIdList.Add(Card.Id); + return true; + } + } + return false; + } + + public bool BrandedBeastActivate() + { + if (CheckWhetherNegated(true, true, CardType.Trap)) return false; + + int desc = -1; + if (ActivateDescription >= Util.GetStringId(CardId.BrandedBeast, 0)) + { + desc = ActivateDescription - Util.GetStringId(CardId.BrandedBeast, 0); + } + Logger.DebugWriteLine("Beast: " + desc.ToString()); + + // destroy + if (ActivateDescription == Util.GetStringId(Card.Id, 0)) + { + ClientCard destroyTarget = null; + ClientCard releaseMonster = null; + List dangerCardList = GetProblematicEnemyCardList(true, false, CardType.Trap); + if (dangerCardList.Count > 0) + { + destroyTarget = dangerCardList[0]; + } + if (destroyTarget == null) + { + if (Duel.Player == 1) + { + if ((CurrentTiming & hintTimingMainEnd) > 0) + { + List targetList = GetNormalEnemyTargetList(true, true, CardType.Trap); + if (targetList.Count > 0) + { + destroyTarget = targetList[0]; + } + } + } + else + { + destroyTarget = Util.GetOneEnemyBetterThanMyBest(true, true); + } + } + + bool forceActivateFlag = DefaultOnBecomeTarget(); + int bystialCount = Bot.MonsterZone.Count(c => c != null && c.IsFaceup() && c.HasSetcode(SetcodeBystial)); + forceActivateFlag |= bystialCount > 0 && Duel.ChainTargets.Count(c => c.Controller == 0 && c.Location == CardLocation.MonsterZone && c.IsFaceup() && c.HasSetcode(SetcodeBystial)) == bystialCount; + forceActivateFlag |= Duel.CurrentChain.Any(c => c.Controller == 1 && c.Location == CardLocation.SpellZone && c.IsCode(_CardId.Raigeki)); + if (destroyTarget == null && forceActivateFlag) + { + releaseMonster = Duel.ChainTargets.FirstOrDefault(c => c.Controller == 0 && c.Location == CardLocation.MonsterZone && c.IsFaceup() && c.HasSetcode(SetcodeBystial)); + if (releaseMonster == null) + { + if (!activatedCardIdList.Contains(CardId.AlbionTheBrandedDragon + 1) && !sendToGYThisTurn.Any(c => c.IsCode(CardId.AlbionTheBrandedDragon))) + { + List brandedDragonList = Bot.MonsterZone.Where(c => c != null && c.IsCode(CardId.AlbionTheBrandedDragon)).OrderBy(c => c.GetDefensePower()).ToList(); + if (brandedDragonList.Count > 0) + { + releaseMonster = brandedDragonList[0]; + } + } + if (releaseMonster == null) + { + releaseMonster = Bot.MonsterZone.Where(c => c != null && c.HasRace(CardRace.Dragon) + && !(c.IsOriginalCode(CardId.FallenOfAlbaz) && Util.ChainContainsCard(CardId.FallenOfAlbaz))).OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + } + } + + List targetList = GetNormalEnemyTargetList(true, true, CardType.Trap); + if (targetList.Count > 0) + { + destroyTarget = targetList[0]; + } + } + + if (destroyTarget != null) + { + if (!activatedCardIdList.Contains(CardId.AlbionTheBrandedDragon + 1) && !sendToGYThisTurn.Any(c => c.IsCode(CardId.AlbionTheBrandedDragon))) + { + List brandedDragonList = Bot.MonsterZone.Where(c => c != null && c.IsCode(CardId.AlbionTheBrandedDragon)).OrderBy(c => c.GetDefensePower()).ToList(); + if (brandedDragonList.Count > 0) + { + releaseMonster = brandedDragonList[0]; + } + } + if (releaseMonster == null) + { + releaseMonster = Bot.MonsterZone.Where(c => c != null && c.HasRace(CardRace.Dragon) + && !(c.IsOriginalCode(CardId.FallenOfAlbaz) && Util.ChainContainsCard(CardId.FallenOfAlbaz))).OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + } + } + + if (releaseMonster != null && destroyTarget != null) + { + activatedCardIdList.Add(Card.Id); + AI.SelectCard(releaseMonster); + AI.SelectNextCard(destroyTarget); + currentDestroyCardList.Add(destroyTarget); + return true; + } + } + + // place + if (Duel.Phase == DuelPhase.End && Bot.HasInGraveyard(CardId.BrandedLost)) + { + activatedCardIdList.Add(Card.Id + 1); + AI.SelectCard(CardId.BrandedLost); + return true; + } + + return false; + } + + public bool BrandedRetributionActivate() + { + if (Card.Location == CardLocation.SpellZone && Duel.LastChainPlayer == 1) + { + if (CheckWhetherNegated(true, true, CardType.Trap)) return false; + bool checkFlag = Bot.Graveyard.Where(c => c != null && c.IsCode(albazFusionMonster)).Count() > 1; + checkFlag |= Bot.MonsterZone.Any(c => c != null && c.IsFaceup() && c.IsCode(new[] { CardId.LubellionTheSearingDragon, CardId.SprindTheIrondashDragon, CardId.AlbaLenatusTheAbyssDragon })); + if (checkFlag) + { + activatedCardIdList.Add(Card.Id); + return true; + } + } + if (Card.Location == CardLocation.Grave) + { + if (CheckWhetherNegated(true, false, CardType.Trap)) return false; + Dictionary> checkDict = new Dictionary>{ + {CardId.BrandedFusion, () => BrandedFusionActivateCheck()}, + {CardId.BrandedLost, () => { + if (Duel.Player == 0 && Duel.Phase >= DuelPhase.End) return false; + if (Bot.HasInHandOrInSpellZone(CardId.BrandedFusion) && BrandedFusionActivateCheck()) return true; + if (Bot.HasInHandOrInSpellZone(CardId.BrandedInWhite) && BrandedInWhiteActivateCheck()) return true; + if (Bot.HasInHandOrInSpellZone(CardId.BrandedInRed) && BrandedInRedActivateCheck() != null) return true; + if (!summoned && Bot.HasInHand(CardId.FallenOfAlbaz) && CheckAlbazFusion()) return true; + if ((Bot.HasInMonstersZone(CardId.BlazingCartesiaTheVirtuous) || (!summoned && Bot.HasInHand(CardId.BlazingCartesiaTheVirtuous)))) return true; + return false; + } }, + {CardId.BrandedInHighSpirits, () => !(Duel.Player == 1 && (fusionToGYFlag || Duel.Phase != DuelPhase.End)) && BrandedInHighSpiritsActivateCheck()}, + {CardId.BrandedInRed, () => BrandedInRedActivateCheck() != null }, + {CardId.BrandedInWhite, BrandedInWhiteActivateCheck }, + {CardId.BrightestBlazingBrandedKing, () => !(Duel.Player == 1 && (fusionToGYFlag || Duel.Phase != DuelPhase.End)) && Bot.GetMonsters().Any(c => c.IsFaceup() && c.IsCode(albazFusionMonster)) }, + {CardId.BrandedOpening, () => Bot.Hand.Count > 2 && !activatedCardIdList.Contains(CardId.BrandedOpening) } + }; + foreach (KeyValuePair> pair in checkDict) + { + ClientCard target = Bot.Graveyard.FirstOrDefault(card => card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + activatedCardIdList.Add(Card.Id); + AI.SelectCard(target); + return true; + } + } + } + return false; + } + + public bool GuardianChimeraActivate() + { + if (CheckWhetherNegated(true, true, CardType.Monster)) return false; + return true; + } + + public bool AlbionTheSanctifireDragonActivate() + { + // spsummon from grave + if (Card.Location == CardLocation.MonsterZone) + { + if (CheckWhetherNegated(true, true, CardType.Monster)) return false; + List allTargetList = Enemy.Graveyard.Where(c => c != null && c.IsMonster() && c.IsCanRevive()).ToList(); + allTargetList.AddRange(Bot.Graveyard.Where(c => c != null && c.IsMonster() && c.IsCanRevive()).ToList()); + + List targetList = new List(); + + // spsummon albaz + if (CheckAlbazFusion(null, out List materialList) && !spSummoningAlbaz) + { + bool albazFlag = materialList.Count > 1; + if (materialList.Count > 0) + { + ClientCard material = materialList[0]; + albazFlag |= material.HasType(CardType.Ritual | CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link); + albazFlag |= material.IsFloodgate() || material.IsOneForXyz() || Util.GetWorstBotMonster().GetDefensePower() < material.Attack; + albazFlag |= Duel.Player == 1 && Duel.Phase == DuelPhase.End && Duel.LastChainPlayer == -1; + } + + if (albazFlag) + { + ClientCard albaz = allTargetList.FirstOrDefault(c => c.IsOriginalCode(CardId.FallenOfAlbaz)); + ClientCard worstMonster = allTargetList.Where(c => c != albaz && !currentDestroyCardList.Contains(c)).OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + if (albaz != null && worstMonster != null + && (GetProblematicEnemyMonster(0, false, false, CardType.Monster) != null || Math.Max(worstMonster.Attack, worstMonster.Defense) <= albaz.Defense)) + { + Logger.DebugWriteLine("Sanctifire 1"); + targetList.AddRange(new[] { albaz, worstMonster }); + spSummoningAlbaz = true; + } + } + } + + // spsummon floogate + if (targetList.Count == 0) + { + ClientCard floogateCard = allTargetList.Where(c => c.IsFloodgate()).OrderByDescending(c => c.GetDefensePower()).FirstOrDefault(); + if (floogateCard != null) + { + // select worst monster + ClientCard worstMonster = allTargetList.Where(c => c != floogateCard).OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + if (worstMonster != null) + { + Logger.DebugWriteLine("Sanctifire 2"); + targetList.AddRange(new[] { floogateCard, worstMonster }); + } + } + } + + // spsummon target + if (targetList.Count == 0 && Duel.LastChainPlayer == 1) + { + List targetedList = Duel.LastChainTargets.Intersect(allTargetList).ToList(); + if (targetedList.Count > 0) + { + ClientCard target = ShuffleList(targetedList)[0]; + ClientCard anotherTarget = null; + if (target.GetDefensePower() >= 2000) + { + // select worst + anotherTarget = allTargetList.Where(c => c != target).OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + } else + { + // select best + anotherTarget = allTargetList.Where(c => c != target).OrderByDescending(c => c.GetDefensePower()).FirstOrDefault(); + } + if (anotherTarget != null) + { + Logger.DebugWriteLine("Sanctifire 3"); + targetList.AddRange(new[] { target, anotherTarget }); + } + } + } + + // spsummon useful monster + if (targetList.Count == 0 && Duel.Player == 1 && Duel.Phase == DuelPhase.End) + { + Dictionary> checkDict = new Dictionary> + { + {CardId.BorreloadFuriousDragon, () => Enemy.GetSpellCount() > 0 }, + {CardId.MirrorjadeTheIcebladeDragon, () => !Bot.HasInMonstersZone(CardId.MirrorjadeTheIcebladeDragon, faceUp: true) && !Bot.HasInSpellZone(CardId.MirrorjadeTheIcebladeDragon, faceUp: true) }, + {CardId.AluberTheJesterOfDespia, () => !activatedCardIdList.Contains(CardId.AluberTheJesterOfDespia) }, + {CardId.SpringansKitt, () => !activatedCardIdList.Contains(CardId.SpringansKitt + 1) }, + }; + + foreach (KeyValuePair> pair in checkDict) + { + ClientCard target = allTargetList.FirstOrDefault(c => c.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + // select worst + ClientCard anotherTarget = allTargetList.Where(c => c != target).OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + targetList.Add(target); + targetList.Add(anotherTarget); + Logger.DebugWriteLine("Sanctifire 4"); + break; + } + } + } + + // avoid evenly match + if (targetList.Count == 0 && Duel.Player == 1 && Enemy.Hand.Count > 0 && Enemy.GetMonsterCount() + Enemy.GetSpellCount() == 0 && (CurrentTiming & hintBattleStart) > 0) + { + ClientCard summonTarget = allTargetList.OrderByDescending(c => c.Attack).FirstOrDefault(); + Dictionary> checkDict = new Dictionary> + { + {CardId.MirrorjadeTheIcebladeDragon, () => !Bot.HasInMonstersZone(CardId.MirrorjadeTheIcebladeDragon, faceUp: true) && !Bot.HasInSpellZone(CardId.MirrorjadeTheIcebladeDragon, faceUp: true) }, + {CardId.AluberTheJesterOfDespia, () => !activatedCardIdList.Contains(CardId.AluberTheJesterOfDespia) }, + }; + foreach (KeyValuePair> pair in checkDict) + { + ClientCard target = allTargetList.FirstOrDefault(c => c.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + summonTarget = target; + break; + } + } + if (summonTarget != null) + { + // select worst + ClientCard anotherTarget = allTargetList.Where(c => c != summonTarget).OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + targetList.Add(summonTarget); + targetList.Add(anotherTarget); + Logger.DebugWriteLine("Sanctifire 5"); + } + } + + if (targetList.Count > 0) + { + AI.SelectMaterials(targetList, HintMsg.SpSummon); + currentDestroyCardList.AddRange(targetList); + activatedCardIdList.Add(Card.Id); + return true; + } + } + // spsummon itself + if (Card.Location == CardLocation.Grave) + { + if (CheckWhetherNegated(true, false, CardType.Monster)) return false; + List botCards = new List { Bot.MonsterZone[2], Bot.MonsterZone[5], Bot.MonsterZone[6] }; + List enemyCards = new List { Enemy.MonsterZone[2], Enemy.MonsterZone[5], Enemy.MonsterZone[6] }; + if (enemyCards.Any(c => c != null && (c.IsFloodgate() || c.IsMonsterDangerous()))) return true; + return botCards.Select(c => c == null ? 0 : c.GetDefensePower()).Sum() < enemyCards.Select(c => c == null ? 0 : c.GetDefensePower()).Sum(); + } + return false; + } + + public bool MirrorjadeTheIcebladeDragonActivate() + { + if (Card.Location != CardLocation.MonsterZone) + { + if (CheckWhetherNegated(true, false, CardType.Monster)) return false; + return true; + } + if (Card.Location == CardLocation.MonsterZone) + { + bool checkFlag = GetProblematicEnemyMonster(0, false, false, CardType.Monster) != null; + if (Enemy.GetMonsterCount() > 0) + { + checkFlag |= Duel.Player == 1 && Duel.Phase == DuelPhase.End && Duel.LastChainPlayer != 0; + int enemyBattlePower = Enemy.BattlingMonster == null ? 0 : Enemy.BattlingMonster.GetDefensePower(); + int botBattlePower = Bot.BattlingMonster == null ? 0 : Bot.BattlingMonster.GetDefensePower(); + checkFlag |= enemyBattlePower > 0 && enemyBattlePower > botBattlePower && Duel.LastChainPlayer != 0 && !currentDestroyCardList.Contains(Enemy.BattlingMonster); + checkFlag |= DefaultOnBecomeTarget() && Duel.LastChainPlayer != 0; + } + if (Duel.CurrentChain.Any(c => c.IsCode(CardId.NibiruThePrimalBeing) && !DefaultCheckWhetherCardIdIsNegated(CardId.NibiruThePrimalBeing))) + { + checkFlag |= Enemy.GetMonsterCount() > 0; + checkFlag |= Bot.HasInMonstersZone(new[] { CardId.TheBystialLubellion, CardId.DespianTragedy, CardId.TriBrigadeMercourier }); + } + + if (checkFlag) + { + Dictionary> checkDict = new Dictionary> + { + {CardId.AlbionTheBrandedDragon, + () =>!sendToGYThisTurn.Any(c => c.IsCode(CardId.AlbionTheBrandedDragon)) && !DefaultCheckWhetherCardIdIsNegated(CardId.AlbionTheBrandedDragon) + && !(Duel.Player == 0 && Bot.HasInMonstersZone(CardId.AlbionTheBrandedDragon) && Bot.HasInGraveyard(CardId.TheBystialLubellion))}, + {CardId.RindbrummTheStrikingDragon, + () => Duel.Player == 1 && Bot.Graveyard.Any(c => c.IsOriginalCode(CardId.FallenOfAlbaz)) && Bot.Hand.Count > 0 + && !activatedCardIdList.Contains(CardId.FallenOfAlbaz) && !DefaultCheckWhetherCardIdIsNegated(CardId.FallenOfAlbaz)}, + {CardId.TitanikladTheAshDragon, () => CheckRemainInDeck(CardId.GuidingQuemTheVirtuous) > 0}, + {CardId.SprindTheIrondashDragon, () => CheckRemainInDeck(CardId.SpringansKitt) > 0}, + {CardId.AlbaLenatusTheAbyssDragon, () => CheckRemainInDeck(CardId.FusionDeployment, CardId.BrandedFusion) > 0 }, + {CardId.LubellionTheSearingDragon, () => true }, + {CardId.AlbionTheSanctifireDragon, () => true } + }; + + foreach (KeyValuePair> pair in checkDict) + { + if (Bot.HasInExtra(pair.Key) && pair.Value()) + { + AI.SelectCard(pair.Key); + return true; + } + } + } + } + return false; + } + + public bool BorreloadFuriousDragonActivate() + { + if (CheckWhetherNegated(true, true, CardType.Monster)) return false; + + // destroy dangerous card + List dangerList = GetProblematicEnemyCardList(true, false, CardType.Monster); + if (dangerList.Count > 0) + { + ClientCard botTarget = Bot.GetMonsters().OrderBy(c => c.GetDefensePower() + (c.IsCode(albazFusionMonster) ? 1 : 0)).FirstOrDefault(); + if (botTarget != null) + { + AI.SelectCard(botTarget); + AI.SelectNextCard(dangerList); + currentDestroyCardList.Add(botTarget); + currentDestroyCardList.Add(dangerList[0]); + activatedCardIdList.Add(Card.Id); + return true; + } + } + + List enemyTargetList = GetNormalEnemyTargetList(true, true, CardType.Monster); + + // become target + if (Duel.LastChainPlayer == 1) + { + List targetedBotMonsterList = Duel.LastChainTargets.Where(c => c.Location == CardLocation.MonsterZone && c.Controller == 0).ToList(); + ClientCard lastChainCard = Util.GetLastChainCard(); + // if it's a negate effect, only destroy not important monster + if (lastChainCard != null && lastChainCard.IsCode(targetNegateIdList)) + { + targetedBotMonsterList = targetedBotMonsterList.Where(c => !c.IsCode(CardId.BlazingCartesiaTheVirtuous) || c.Attack < 2500).OrderBy(c => c.Attack).ToList(); + } + if (targetedBotMonsterList.Count > 0) + { + AI.SelectCard(targetedBotMonsterList); + AI.SelectNextCard(enemyTargetList); + currentDestroyCardList.Add(targetedBotMonsterList[0]); + currentDestroyCardList.Add(enemyTargetList[0]); + activatedCardIdList.Add(Card.Id); + return true; + } + } + + // end phase + if (Duel.Player == 1 && Duel.Phase == DuelPhase.End) + { + List botTargetList = Bot.MonsterZone.Where(c => c != null && c.GetDefensePower() <= 2500).OrderBy(c => c.GetDefensePower()).ToList(); + if (botTargetList.Count > 0) + { + AI.SelectCard(botTargetList); + AI.SelectNextCard(enemyTargetList); + currentDestroyCardList.Add(botTargetList[0]); + currentDestroyCardList.Add(enemyTargetList[0]); + activatedCardIdList.Add(Card.Id); + return true; + } + } + + return false; + } + + public bool LubellionTheSearingDragonActivate() + { + if (CheckWhetherNegated(true, true, CardType.Monster)) return false; + if (Card.Location == CardLocation.MonsterZone) + { + int fusionTarget = LubellionTheSearingDragonFusionTarget(Bot.ExtraDeck, out _); + if (fusionTarget > 0) + { + activatedCardIdList.Add(Card.Id); + return true; + } + } + return false; + } + + public int LubellionTheSearingDragonFusionTarget(IList cards, out ClientCard target) + { + target = null; + bool hasAlbaz = Bot.Banished.Any(c => c != null && c.IsFaceup() && c.IsOriginalCode(CardId.FallenOfAlbaz)); + hasAlbaz |= Bot.Graveyard.Any(c => c != null && c.IsFaceup() && c.IsOriginalCode(CardId.FallenOfAlbaz)); + Dictionary> checkDict = new Dictionary> + { + {CardId.MirrorjadeTheIcebladeDragon, () => hasAlbaz && !DefaultCheckWhetherCardIdIsNegated(CardId.MirrorjadeTheIcebladeDragon) }, + {CardId.GranguignolTheDuskDragon, () => Bot.HasInBanished(CardId.BlazingCartesiaTheVirtuous) }, + {CardId.BorreloadFuriousDragon, () => + { + int darkDragonCount = Bot.Banished.Where(c => c.IsFaceup() && c.HasRace(CardRace.Dragon) && c.HasAttribute(CardAttribute.Dark) + && !c.IsCode(cannotBeFusionMaterialIdList) ).Count(); + darkDragonCount += Bot.Graveyard.Where(c => c.HasRace(CardRace.Dragon) && c.HasAttribute(CardAttribute.Dark) + && !c.IsCode(cannotBeFusionMaterialIdList) + && (Duel.Player == 1 || !CheckWhetherShouldKeepInGrave(c)) ).Count(); + return darkDragonCount >= 2; + } }, + {CardId.RindbrummTheStrikingDragon, () => hasAlbaz && Bot.HasInBanished(CardId.TriBrigadeMercourier) }, + {CardId.TitanikladTheAshDragon, () => + { + if (!hasAlbaz) return false; + ClientCard enemyMonster = Util.GetBestEnemyMonster(true); + ClientCard botMonster = Util.GetBestBotMonster(true); + int enemyPower = enemyMonster == null ? 0 : enemyMonster.GetDefensePower(); + int botPower = botMonster == null ? 0 : botMonster.Attack; + if (enemyPower > 0 && enemyPower >= botPower) + { + List materialList = new List(Bot.Banished); + materialList.AddRange(Bot.Graveyard); + foreach (ClientCard material in materialList) + { + if (material != null && material.IsFaceup() && material.Attack >= 2500 && (2900 + material.Level >= enemyPower)) + { + return true; + } + } + } + return false; + } }, + {CardId.DespianQuaeritis, () => { + if (!Enemy.MonsterZone.Any(c => c != null && c.IsFaceup() && c.Attack > 2500 && !(c.HasType(CardType.Fusion) && c.Level >= 8))) return false; + bool checkFlag = Bot.Banished.Any(c => c != null && c.IsFaceup() && c.HasSetcode(SetcodeDespain)); + checkFlag |= Bot.Graveyard.Any(c => c != null && c.IsFaceup() && c.HasSetcode(SetcodeDespain)); + + return checkFlag; + } }, + {CardId.AlbaLenatusTheAbyssDragon, () => hasAlbaz && !Bot.HasInExtra(CardId.AlbionTheBrandedDragon) }, + {CardId.AlbionTheBrandedDragon, () => { + if (activatedCardIdList.Contains(CardId.AlbionTheBrandedDragon) || DefaultCheckWhetherCardIdIsNegated(CardId.AlbionTheBrandedDragon)) return false; + bool checkFlag = Bot.Banished.Any(c => c != null && c.IsFaceup() && c.HasAttribute(CardAttribute.Light)); + checkFlag |= Bot.Graveyard.Any(c => c != null && c.IsFaceup() && c.HasAttribute(CardAttribute.Light)); + + return checkFlag; + }} + }; + + foreach (KeyValuePair> pair in checkDict) + { + target = cards.FirstOrDefault(card => card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + return pair.Key; + } + } + + target = null; + return 0; + } + + public bool AlbaLenatusTheAbyssDragonSpSummon() + { + // use albaz + enemy's dragon monster + List enemyDragon = Enemy.GetMonsters().Where(c => c != null && c.IsFaceup() && !c.IsCode(cannotBeFusionMaterialIdList) && c.HasRace(CardRace.Dragon)).ToList(); + if (enemyDragon.Count > 0) + { + bool successFlag = enemyDragon.Count > 1; + int bestBotPower = Util.GetBestAttack(Bot); + successFlag |= enemyDragon.Any(c => c.GetDefensePower() >= bestBotPower); + if (successFlag) + { + if (!enemyDragon.Any(c => c.IsCode(CardId.FallenOfAlbaz))) + { + ClientCard botAlbaz = Bot.MonsterZone.FirstOrDefault(c => c != null && c.IsCode(CardId.FallenOfAlbaz)); + if (botAlbaz != null) + { + enemyDragon.Add(botAlbaz); + } + } + AI.SelectMaterials(enemyDragon); + return true; + } + } + + return false; + } + + public bool AlbaLenatusTheAbyssDragonActivate() + { + if (CheckWhetherNegated(true, false, CardType.Monster)) return false; + activatedCardIdList.Add(Card.Id); + return true; + } + + public bool GranguignolTheDuskDragonActivate() + { + int desc = -1; + if (ActivateDescription >= Util.GetStringId(CardId.GranguignolTheDuskDragon, 0)) + { + desc = ActivateDescription - Util.GetStringId(CardId.GranguignolTheDuskDragon, 0); + } + Logger.DebugWriteLine("granguignol: " + desc.ToString()); + + // send to GY + if (ActivateDescription == -1 || ActivateDescription == Util.GetStringId(CardId.GranguignolTheDuskDragon, 0)) + { + if (CheckWhetherNegated(true, true, CardType.Monster) || CheckWhetherWillbeRemoved()) return false; + int checkId = GranguignolTheDuskDragonSendToGYTarget(null, out _); + if (checkId > 0) + { + activatedCardIdList.Add(Card.Id); + return true; + } + } + // spsummon + if (ActivateDescription == Util.GetStringId(CardId.GranguignolTheDuskDragon, 1)) + { + if (CheckWhetherNegated(true, Card.Location == CardLocation.MonsterZone, CardType.Monster)) return false; + activatedCardIdList.Add(Card.Id + 1); + return true; + } + + return false; + } + + public int GranguignolTheDuskDragonSendToGYTarget(IList cards, out ClientCard target) + { + bool needSendBranded = Bot.HasInGraveyard(CardId.BrandedRetribution) && CheckRemainInDeck(CardId.BrandedFusion) > 0; + if (CheckRemainInDeck(CardId.BrandedRetribution) > 0) + { + needSendBranded |= Bot.Graveyard.Any(c => c != null && c.HasType(CardType.Spell | CardType.Trap) && c.HasSetcode(SetcodeBranded) + && !(fusionToGYFlag && c.IsCode(CardId.BrightestBlazingBrandedKing, CardId.BrandedInHighSpirits))); + needSendBranded |= !activatedCardIdList.Contains(CardId.AlbionTheShroudedDragon) && !CheckWhetherWillbeRemoved() && Bot.HasInHandOrInGraveyard(CardId.AlbionTheShroudedDragon); + needSendBranded |= Duel.CurrentChain.Any(c => c.Controller == 0 && c.Location == CardLocation.Grave && c.IsCode(CardId.BystialSaronir)); + } + List>> checkList = new List>> + { + new KeyValuePair>(CardId.BystialSaronir, () => !activatedCardIdList.Contains(CardId.BystialSaronir) && needSendBranded), + new KeyValuePair>(CardId.AlbionTheShroudedDragon, () => !activatedCardIdList.Contains(CardId.AlbionTheShroudedDragon) && needSendBranded ), + new KeyValuePair>(CardId.AlbionTheBrandedDragon, () => !activatedCardIdList.Contains(CardId.AlbionTheBrandedDragon + 1) && !sendToGYThisTurn.Any(c => c.IsCode(CardId.AlbionTheBrandedDragon)) ), + new KeyValuePair>(CardId.TitanikladTheAshDragon, () => !activatedCardIdList.Contains(CardId.TitanikladTheAshDragon) && !sendToGYThisTurn.Any(c => c.IsCode(CardId.TitanikladTheAshDragon)) + && CheckRemainInDeck(CardId.GuidingQuemTheVirtuous, CardId.FallenOfAlbaz) > 0), + new KeyValuePair>(CardId.TheBystialLubellion, () => Bot.HasInMonstersZone(new[] {CardId.AlbionTheBrandedDragon, CardId.TitanikladTheAshDragon}) + && CheckRemainInDeck(CardId.BrandedLost, CardId.BrandedBeast) > 0 ), + new KeyValuePair>(CardId.SprindTheIrondashDragon, () => !activatedCardIdList.Contains(CardId.SprindTheIrondashDragon) && !sendToGYThisTurn.Any(c => c.IsCode(CardId.SprindTheIrondashDragon)) + && CheckRemainInDeck(CardId.SpringansKitt) > 0), + new KeyValuePair>(CardId.DespianLuluwalilith, () => CheckRemainInDeck(CardId.BlazingCartesiaTheVirtuous, CardId.GuidingQuemTheVirtuous) > 0 ), + new KeyValuePair>(CardId.AlbionTheShroudedDragon, () => true ), + }; + + foreach (KeyValuePair> pair in checkList) + { + if (cards == null) + { + if ((CheckRemainInDeck(pair.Key) > 0 || Bot.HasInExtra(pair.Key)) && pair.Value()) + { + target = null; + return pair.Key; + } + } else + { + ClientCard tg = cards.FirstOrDefault(c => c.IsOriginalCode(pair.Key)); + if (tg != null && pair.Value()) + { + target = tg; + return pair.Key; + } + } + } + + target = null; + return 0; + } + + public bool DespianQuaeritisActivate() + { + if (Card.Location == CardLocation.MonsterZone && Duel.Phase == DuelPhase.Main1 && !CheckWhetherNegated(true, true, CardType.Monster)) + { + if ((CurrentTiming & hintTimingMainEnd) != 0 && Duel.Player == 1) + { + int bestBotPower = Util.GetBestPower(Bot, false); + if (Enemy.GetMonsters().Any(c => c.GetDefensePower() >= bestBotPower && c.IsAttack() && !(c.HasType(CardType.Fusion) && c.Level >= 8))) { + activatedCardIdList.Add(Card.Id); + return true; + } + } + if (Duel.Player == 0 && Enemy.GetMonsters().Any(c => c.IsAttack() && !(c.HasType(CardType.Fusion) && c.Level >= 8))) + { + activatedCardIdList.Add(Card.Id); + return true; + } + } + if (Card.Location != CardLocation.MonsterZone) + { + if (CheckWhetherNegated(true, false, CardType.Monster)) return true; + activatedCardIdList.Add(Card.Id + 1); + return true; + } + return false; + } + + public bool SprindTheIrondashDragonActivate() + { + // search + if (Card.Location == CardLocation.Grave) + { + if (CheckWhetherNegated(true, false, CardType.Monster)) return false; + activatedCardIdList.Add(Card.Id + 1); + return true; + } + // destroy + if (Card.Location == CardLocation.MonsterZone) + { + if (CheckWhetherNegated(true, true, CardType.Monster)) return false; + int moveDest = SprindTheIrondashDragonMoveZone(0, Card); + if (moveDest > 0) + { + activatedCardIdList.Add(Card.Id); + return true; + } + } + return false; + } + + public int SprindTheIrondashDragonMoveZone(int available = 0, ClientCard selfCard = null) + { + int maxZone = -1; + int maxValue = 0; + for (int zoneId = 0; zoneId < 5; ++zoneId) + { + // check whether can move + if (Bot.MonsterZone[zoneId] != null) continue; + int zone = (int)System.Math.Pow(2, zoneId); + if (available > 0 && (available & zone) == 0) continue; + + int currentValue = SprindTheIrondashDragonDestroyValue(zoneId, selfCard); + if (currentValue > maxValue) + { + maxZone = zone; + maxValue = currentValue; + } + } + return maxZone; + } + + public int SprindTheIrondashDragonDestroyValue(int zoneId, ClientCard selfCard = null) + { + int value = 0; + if (zoneId == 1 || zoneId == 3) + { + ClientCard botMonsterInExtraZone = Bot.MonsterZone[(zoneId + 9) / 2]; + if (botMonsterInExtraZone != null && botMonsterInExtraZone != selfCard && botMonsterInExtraZone.IsFaceup()) value -= 5; + + ClientCard enemyMonserInExtraZone = Enemy.MonsterZone[(11 - zoneId) / 2]; + if (enemyMonserInExtraZone != null && enemyMonserInExtraZone.IsFaceup()) value += 2; + } + ClientCard botSpell = Bot.SpellZone[zoneId]; + if (botSpell != null && botSpell.IsFaceup()) value--; + ClientCard enemyMonster = Enemy.MonsterZone[5 - zoneId]; + if (enemyMonster != null && enemyMonster.IsFaceup()) + { + value++; + if (enemyMonster.IsFloodgate() || enemyMonster.IsMonsterDangerous()) value += 5; + } + ClientCard enemySpell = Enemy.SpellZone[5 - zoneId]; + if (enemySpell != null && enemySpell.IsFaceup()) + { + value++; + if (enemySpell.IsFloodgate()) value += 5; + } + + return value; + } + + public bool TitanikladTheAshDragonActivate() + { + if (Card.Location == CardLocation.Grave) + { + if (CheckWhetherNegated(true, false, CardType.Monster)) return false; + activatedCardIdList.Add(Card.Id); + return true; + } + return false; + } + + public bool RindbrummTheStrikingDragonActivate() + { + if (Card.Location == CardLocation.MonsterZone) + { + if (CheckWhetherNegated(true, true, CardType.Monster)) return false; + bool checkFlag = false; + + ClientCard lastChainCard = Util.GetLastChainCard(); + if (lastChainCard != null) + { + checkFlag = Duel.LastChainPlayer == 1; + checkFlag |= Duel.LastChainPlayer == 0 && lastChainCard.IsCode(CardId.MirrorjadeTheIcebladeDragon) && lastChainCard.Location == CardLocation.MonsterZone && Enemy.GetMonsterCount() == 0; + } + + if (checkFlag) + { + activatedCardIdList.Add(Card.Id); + return true; + } + } + if (Card.Location == CardLocation.Grave) + { + if (CheckWhetherNegated(true, true, CardType.Monster) || Duel.CurrentChain.Any(c => c.Controller == 0 && c.IsCode(CardId.GuidingQuemTheVirtuous))) return false; + + ClientCard albaz = Bot.Graveyard.FirstOrDefault(c => c.IsOriginalCode(CardId.FallenOfAlbaz)); + bool checkFlag = Card.IsCanRevive() && Enemy.MonsterZone.Any(c => c != null && c.IsFaceup() && c.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link)); + bool albazFlag = CheckAlbazFusion(null, out List materialList) && albaz != null && !spSummoningAlbaz; + if (albazFlag) + { + checkFlag |= materialList.Count > 1; + if (materialList.Count > 0) + { + ClientCard material = materialList[0]; + checkFlag |= material.HasType(CardType.Ritual | CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link); + checkFlag |= material.IsFloodgate() || material.IsOneForXyz() || Util.GetWorstBotMonster()?.GetDefensePower() < material.Attack; + checkFlag |= Duel.Player == 1 && Duel.Phase == DuelPhase.End && Duel.LastChainPlayer == -1; + } + } + + if (checkFlag) + { + albaz = Bot.Graveyard.Where(c => c.IsCode(CardId.FallenOfAlbaz)).OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + + if (checkFlag && albaz != null) + { + spSummoningAlbaz = true; + activatedCardIdList.Add(Card.Id + 1); + AI.SelectCard(albaz); + return true; + } + } + } + return false; + } + + public bool AlbionTheBrandedDragonActivate() + { + if (Card.Location == CardLocation.MonsterZone) + { + if (CheckWhetherNegated(true, true, CardType.Monster)) return false; + int fusionTarget = AlbionTheBrandedDragonFusionTarget(Bot.ExtraDeck, out _); + if (fusionTarget > 0) + { + activatedCardIdList.Add(Card.Id); + return true; + } + } + if (Card.Location == CardLocation.Grave) + { + if (CheckWhetherNegated(true, false, CardType.Monster)) return false; + activatedCardIdList.Add(Card.Id + 1); + return true; + } + return false; + } + + public int AlbionTheBrandedDragonFusionTarget(IList cards, out ClientCard target) + { + target = null; + Dictionary> checkDict = new Dictionary> + { + {CardId.MirrorjadeTheIcebladeDragon, () => { + bool checkFlag = !CheckWhetherNegated() && CheckShouldNoMoreSpSummon(); + checkFlag |= Bot.Graveyard.Any(c => c != null && !sendToGYThisTurn.Contains(c) && !c.IsCode(cannotBeFusionMaterialIdList) + && c.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link)); + return checkFlag; + } }, + {CardId.LubellionTheSearingDragon, () => + { + if (!activatedCardIdList.Contains(CardId.LubellionTheSearingDragon)) + { + List checkMaterialList = new List(Bot.GetMonsters()); + checkMaterialList.AddRange(Bot.Graveyard); + bool albazChecked = false; + bool hasOriginalAlbaz = checkMaterialList.Any(c => c.IsOriginalCode(CardId.FallenOfAlbaz)); + foreach (ClientCard checkCard in checkMaterialList) + { + if (!albazChecked && checkCard.IsCode(CardId.FallenOfAlbaz) && (!hasOriginalAlbaz || !checkCard.IsOriginalCode(CardId.AlbionTheShroudedDragon))) + { + albazChecked = true; + continue; + } + if (checkCard.HasAttribute(CardAttribute.Dark)) return true; + } + if (Bot.HasInHand(CardId.TriBrigadeMercourier) && Bot.Hand.Count >= 2) return true; + } + return false; + } }, + {CardId.BorreloadFuriousDragon, () => { + if (Enemy.GetMonsterCount() + Enemy.GetSpellCount() > 0) + { + int darkDragonCount = Bot.Graveyard.Where(c => c.HasRace(CardRace.Dragon) && c.HasAttribute(CardAttribute.Dark) + && !c.IsCode(cannotBeFusionMaterialIdList) + && (Duel.Player == 1 || !CheckWhetherShouldKeepInGrave(c)) ).Count(); + if (Duel.Player == 1 && Bot.GetMonsters().Any(c => c.HasRace(CardRace.Dragon) && c.HasAttribute(CardAttribute.Dark) && !c.IsCode(cannotBeFusionMaterialIdList))) { + darkDragonCount ++; + } + return darkDragonCount >= 2; + } + return false; + } }, + {CardId.AlbionTheSanctifireDragon, () => + { + ClientCard albaz = Bot.Graveyard.FirstOrDefault(c => c.IsCode(CardId.FallenOfAlbaz)); + ClientCard lightSpellcaster = Bot.Graveyard.FirstOrDefault(c => c.HasRace(CardRace.SpellCaster) && c.HasAttribute(CardAttribute.Light)); + int remainMonsterCount = Enemy.GetGraveyardMonsters().Count; + remainMonsterCount += Bot.Graveyard.Where(c => c.IsMonster() && c != albaz && c != lightSpellcaster).Count(); + remainMonsterCount += Bot.HasInHand(_CardId.MaxxC) ? 1 : 0; + return remainMonsterCount >= 2; + } }, + {CardId.RindbrummTheStrikingDragon, () => Bot.HasInGraveyard(CardId.TriBrigadeMercourier) }, + {CardId.DespianQuaeritis, () => + { + bool checkFlag = Enemy.MonsterZone.Any(c => c != null && c.IsFaceup() && c.Attack >= 2500 && !(c.HasType(CardType.Fusion) && c.Level >= 8)); + if (checkFlag) + { + ClientCard despian = Bot.Graveyard.Where(c => c != null && c.HasSetcode(SetcodeDespain) && !CheckWhetherShouldKeepInGrave(c)) + .OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + if (despian == null) + { + despian = Bot.MonsterZone.Where(c => c != null && c.HasSetcode(SetcodeDespain)).OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + } + if (despian != null) + { + return Bot.Graveyard.Any(c => c.HasAttribute(CardAttribute.Light | CardAttribute.Dark) && !CheckWhetherShouldKeepInGrave(c) && c != despian); + } + } + + return false; + } }, + {CardId.TitanikladTheAshDragon, () => + { + ClientCard albaz = Bot.Graveyard.FirstOrDefault(c => c != null && c.IsOriginalCode(CardId.FallenOfAlbaz)); + if (albaz == null) + { + albaz = Bot.Graveyard.FirstOrDefault(c => c != null && c.IsCode(CardId.FallenOfAlbaz)); + } + foreach (ClientCard material in Bot.Graveyard) + { + if (material != null && material != albaz && material.IsMonster() && material.Attack >= 2500 && !material.IsCode(cannotBeFusionMaterialIdList)) + { + bool checkFlag = !Util.IsTurn1OrMain2() && Enemy.GetMonsterCount() == 0; + checkFlag |= !CheckWhetherShouldKeepInGrave(material); + return checkFlag; + } + } + return false; + } }, + {CardId.AlbaLenatusTheAbyssDragon, () => + { + if (Util.GetOneEnemyBetterThanMyBest() == null) + { + ClientCard albaz = Bot.Graveyard.FirstOrDefault(c => c != null && c.IsOriginalCode(CardId.FallenOfAlbaz)); + if (albaz == null) + { + albaz = Bot.Graveyard.FirstOrDefault(c => c != null && c.IsCode(CardId.FallenOfAlbaz)); + } + foreach (ClientCard material in Bot.Graveyard) + { + if (material != null && material != albaz && material.IsMonster() && material.HasRace(CardRace.Dragon) && !material.IsCode(cannotBeFusionMaterialIdList)) + { + return true; + } + } + } + return false; + } }, + {CardId.GranguignolTheDuskDragon, () => + { + if (cards == null) return false; + return true; + } } + }; + + foreach (KeyValuePair> pair in checkDict) + { + target = cards.FirstOrDefault(card => card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + return pair.Key; + } + } + + target = null; + return 0; + } + + public bool DespianLuluwalilithActivate() + { + if (Card.Location == CardLocation.MonsterZone) + { + if (CheckWhetherNegated(true, true, CardType.Monster)) return false; + activatedCardIdList.Add(Card.Id); + return true; + } + if (Card.Location == CardLocation.Grave) + { + if (CheckWhetherNegated(true, false, CardType.Monster)) return false; + if (CheckRemainInDeck(CardId.GuidingQuemTheVirtuous, CardId.BlazingCartesiaTheVirtuous) > 0) + { + activatedCardIdList.Add(Card.Id + 1); + return true; + } + } + return false; + } + + public bool SetForChimera() + { + if (Card.Level <= 4) return false; + if (Bot.GetMonsterCount() > 0 || !Bot.HasInHandOrInSpellZone(CardId.BrandedInWhite) || !Bot.HasInExtra(CardId.GuardianChimera)) return false; + if (DefaultCheckWhetherCardIdIsNegated(CardId.GuardianChimera) || CheckWhetherNegated(true, true, CardType.Monster)) return false; + if (Enemy.MonsterZone.All(c => c == null) && Enemy.SpellZone.All(c => c == null)) return false; + + for (int handIndex1 = 0; handIndex1 < Bot.Hand.Count - 1; ++ handIndex1) + { + ClientCard hand1 = Bot.Hand[handIndex1]; + if (!hand1.IsMonster() || hand1.IsCode(Card.Id) || Card.IsCode(hand1.Id)) continue; + for (int handIndex2 = handIndex1 + 1; handIndex2 < Bot.Hand.Count; ++ handIndex2) + { + ClientCard hand2 = Bot.Hand[handIndex2]; + if (!hand2.IsMonster()) continue; + if (hand2.IsCode(Card.Id) || Card.IsCode(hand2.Id) || hand2.IsCode(hand1.Id) || hand1.IsCode(hand2.Id)) continue; + bool checkFlag = Card.HasRace(CardRace.Dragon) || hand1.HasRace(CardRace.Dragon) || hand2.HasRace(CardRace.Dragon); + if (checkFlag) + { + summoned = true; + return true; + } + } + } + + return false; + } + + public bool AdvanceSummon() + { + if (Card.Level < 5) return false; + + List releaseGoal = Bot.MonsterZone.Where(c => c != null && c.IsFaceup() && !c.IsDisabled() && c.IsCode(10158145)).ToList(); + if (releaseGoal.Count > 0) + { + if (Card.Level <= 6) + { + AI.SelectMaterials(releaseGoal); + summoned = true; + return true; + } + + if (Card.Level >= 7) + { + if (releaseGoal.Count < 2) + { + ClientCard anotherMaterial = Bot.MonsterZone.Where(c => c != null && !releaseGoal.Contains(c)).OrderBy(c => c.GetDefensePower()).FirstOrDefault(); + if (anotherMaterial.GetDefensePower() > Card.Attack) return false; + releaseGoal.Add(anotherMaterial); + } + if (releaseGoal.Count >= 2) + { + AI.SelectMaterials(releaseGoal); + summoned = true; + return true; + } + } + } + return false; + } + + public bool SpellSetCheck() + { + if (Duel.Phase == DuelPhase.Main1 && Bot.HasAttackingMonster() && Duel.Turn > 1) return false; + switch (Card.Id) + { + case CardId.BrandedInHighSpirits: + { + bool checkFlag = (Bot.HasInMonstersZone(CardId.GuidingQuemTheVirtuous) + || (CheckRemainInDeck(CardId.GuidingQuemTheVirtuous) > 0 && sendToGYThisTurn.Any(c => c.IsCode(CardId.TitanikladTheAshDragon)))); + if (!checkFlag) return false; + } + break; + case CardId.BrandedOpening: + { + bool checkFlag = CheckRemainInDeck(CardId.AluberTheJesterOfDespia, CardId.GuidingQuemTheVirtuous) > 0; + if (!checkFlag) return false; + } + break; + case CardId.BrightestBlazingBrandedKing: + { + bool checkFlag = Bot.MonsterZone.Any(c => c != null && c.IsFaceup() && c.IsCode(albazFusionMonster)); + if (!checkFlag) return false; + } + break; + case CardId.BrandedBeast: + { + bool checkFlag = Bot.HasInGraveyard(CardId.BrandedLost) || Bot.MonsterZone.Any(c => c != null && c.IsFaceup() && c.HasSetcode(SetcodeBystial)); + checkFlag |= Bot.HasInHand(CardId.BystialSaronir) && (Enemy.Graveyard.Any(c => CheckBystialCanBanish(c)) || Bot.Graveyard.Any(c => CheckBystialCanBanish(c))); + if (!checkFlag) return false; + } + break; + case CardId.BrandedRetribution: + { + bool checkFlag = Bot.Graveyard.Where(c => c.IsCode(albazFusionMonster)).Count() > 1; + checkFlag |= Bot.MonsterZone.Any(c => c != null && c.IsFaceup() && c.IsCode(albazFusionMonster)); + if (!checkFlag) return false; + } + break; + default: + break; + } + + // select place + if ((Card.IsTrap() || Card.HasType(CardType.QuickPlay))) + { + List avoid_list = new List(); + int setForInfiniteImpermanence = 0; + for (int i = 0; i < 5; ++i) + { + if (Enemy.SpellZone[i] != null && Enemy.SpellZone[i].IsFaceup() && Bot.SpellZone[4 - i] == null) + { + avoid_list.Add(4 - i); + setForInfiniteImpermanence += (int)System.Math.Pow(2, 4 - i); + } + } + if (Bot.HasInHand(_CardId.InfiniteImpermanence)) + { + if (Card.IsCode(_CardId.InfiniteImpermanence)) + { + AI.SelectPlace(setForInfiniteImpermanence); + return true; + } + else + { + SelectSTPlace(Card, false, avoid_list); + return true; + } + } + else + { + SelectSTPlace(); + } + return true; + } + + else if (Enemy.HasInSpellZone(_CardId.AntiSpellFragrance, true) || Bot.HasInSpellZone(_CardId.AntiSpellFragrance, true)) + { + if (Card.IsSpell() && !Bot.HasInSpellZone(Card.Id)) + { + SelectSTPlace(); + return true; + } + } + + return false; + } + + protected override bool DefaultSetForDiabellze() + { + if (base.DefaultSetForDiabellze()) + { + SelectSTPlace(Card, true); + return true; + } + return false; + } + + // for Sanctifire Dragon spsummoned monster + public bool FloogateActivate() + { + if (Card.Owner != 1 && !Card.IsFloodgate()) return false; + if (CheckWhetherNegated()) return false; + if (Executors.Any(e => e != null && e.Type == ExecutorType.Activate && e.CardId == Card.Id)) return false; + if (Duel.LastChainPlayer == 1) + { + ClientCard lastChainCard = Util.GetLastChainCard(); + if (lastChainCard != null && lastChainCard.IsFaceup() && CheckCanBeTargeted(lastChainCard, true, CardType.Monster) + && (lastChainCard.Location == CardLocation.MonsterZone || lastChainCard.Location == CardLocation.SpellZone)) + { + AI.SelectCard(lastChainCard); + } + } + + return Duel.LastChainPlayer == 1; + } + } +} \ No newline at end of file diff --git a/libWindbot/Game/AI/Decks/SuperheavySamuraiExecutor.cs b/libWindbot/Game/AI/Decks/SuperheavySamuraiExecutor.cs index 261dc9b..b0911a0 100644 --- a/libWindbot/Game/AI/Decks/SuperheavySamuraiExecutor.cs +++ b/libWindbot/Game/AI/Decks/SuperheavySamuraiExecutor.cs @@ -80,7 +80,8 @@ public class CardId public SuperheavySamuraiExecutor(GameAI ai, Duel duel) : base(ai, duel) { - AddExecutor(ExecutorType.Activate, CardId.PSYFramelordOmega); + AddExecutor(ExecutorType.Repos, MonsterRepos); + AddExecutor(ExecutorType.Activate, CardId.PSYFramelordOmega,PSYFunction); AddExecutor(ExecutorType.Activate, CardId.IP,IPFunction); AddExecutor(ExecutorType.Activate, CardId.Sarutobi,SarutobiFunction); AddExecutor(ExecutorType.Activate, CardId.Unicorn,UnicornFunction); @@ -101,9 +102,8 @@ public SuperheavySamuraiExecutor(GameAI ai, Duel duel) AddExecutor(ExecutorType.SpSummon, CardId.Scales); AddExecutor(ExecutorType.Activate, CardId.Scales,ScalesFunction); - //Synchron - AddExecutor(ExecutorType.SpSummon, CardId.ASStardustDragon,ASStardustDragonSynchronFunction2); - AddExecutor(ExecutorType.SpSummon, CardId.Fleur,FleurSynchronFunction2); + //Synchron + AddExecutor(ExecutorType.SpSummon, CardId.PSYFramelordOmega,PSYFramelordOmegaSynchronFunction); //Pendulum AddExecutor(ExecutorType.Activate, CardId.Wakaushi,WakaushiFunction); @@ -183,7 +183,6 @@ public SuperheavySamuraiExecutor(GameAI ai, Duel duel) //Synchron AddExecutor(ExecutorType.SpSummon, CardId.Masurawo,MasurawoSynchronFunction); AddExecutor(ExecutorType.SpSummon, CardId.Sarutobi,DeSynchronFunction); - AddExecutor(ExecutorType.SpSummon, CardId.PSYFramelordOmega); //equip Soulhorns AddExecutor(ExecutorType.Activate, CardId.Soulhorns,SoulhornsEquipFunction); @@ -219,6 +218,24 @@ public override bool OnSelectHand() { return true; } + private bool MonsterRepos() + { + if (Card.IsFacedown()) + return true; + if (Card.IsFaceup() && Card.IsAttack() && (Card.Id == CardId.Masurawo || Card.Id == CardId.Sarutobi)) + return true; + return false; + } + public override CardPosition OnSelectPosition(int cardId, IList positions) + { + YGOSharp.OCGWrapper.NamedCard cardData = YGOSharp.OCGWrapper.NamedCard.Get(cardId); + if (cardData != null) + { + if (cardId == CardId.Masurawo || cardId == CardId.Sarutobi) + return CardPosition.FaceUpDefence; + } + return 0; + } public override int OnSelectPlace(int cardId, int player, CardLocation location, int available) { if (player == 0 && location == CardLocation.MonsterZone) @@ -597,14 +614,6 @@ private bool FleurSynchronFunction() AI.SelectMaterials(materials_lists[0]); return true; } - private bool FleurSynchronFunction2() - { - var materials_lists = Util.GetSynchroMaterials(Bot.MonsterZone,10,1,1,false,false,null, - card => { return !FinalCards(card.Id); }); - if (materials_lists.Count <= 0) return false; - AI.SelectMaterials(materials_lists[0]); - return true; - } private bool DeSynchronFunction() { AI.SelectPosition(CardPosition.FaceUpDefence); @@ -630,17 +639,26 @@ private bool ASStardustDragonSynchronFunction() { return (Bot.HasInExtra(CardId.Fleur) || Bot.HasInExtra(CardId.Masurawo)); } - return false; - } - private bool ASStardustDragonSynchronFunction2() - { - if (!activate_Scales || !activate_PSY) return false; - if (Bot.HasInGraveyard(CardId.Motorbike) || Bot.HasInGraveyard(CardId.PsyFramegearGamma)) + else if (Bot.HasInMonstersZone(CardId.Motorbike)) { - return (Bot.HasInExtra(CardId.Fleur) || Bot.HasInExtra(CardId.Masurawo)); + AI.SelectMaterials(CardId.Motorbike); + return true; + } + else if (Bot.HasInMonstersZone(CardId.PsyFramegearGamma)) + { + AI.SelectMaterials(CardId.PsyFramegearGamma); + return true; } return false; } + private bool PSYFramelordOmegaSynchronFunction() + { + if (Bot.HasInMonstersZone(CardId.Motorbike)) + AI.SelectMaterials(CardId.Motorbike); + else if (Bot.HasInMonstersZone(CardId.PsyFramegearGamma)) + AI.SelectMaterials(CardId.PsyFramegearGamma); + return activate_PSY || activate_Scales; + } private bool SavageDragonFunction() { if (Duel.LastChainPlayer == 1) @@ -1156,6 +1174,11 @@ private bool IPLinkFunction() AI.SelectMaterials(materials); return true; } + private bool PSYFunction() + { + activate_PSY = true; + return true; + } private bool IPFunction() { if (Duel.LastChainPlayer == 0) return false; @@ -1193,4 +1216,4 @@ private bool SarutobiFunction() return true; } } -} \ No newline at end of file +} diff --git a/libWindbot/Game/AI/DefaultExecutor.cs b/libWindbot/Game/AI/DefaultExecutor.cs index 0a49ca3..8fb2fb8 100644 --- a/libWindbot/Game/AI/DefaultExecutor.cs +++ b/libWindbot/Game/AI/DefaultExecutor.cs @@ -181,6 +181,7 @@ protected class _CardId public const int DuelDragonToken = 60025884; public const int SeleneQueenOfTheMasterMagicians = 45819647; public const int TheWingedDragonofRaSphereMode = 10000080; + public const int SelettriceVaalmonica = 23093373; public const int RockOfTheVanquisher = 28168628; public const int SpiralDischarge = 29477860; @@ -302,7 +303,8 @@ protected DefaultExecutor(GameAI ai, Duel duel) {_CardId.DuelLinkDragonTheDuelDragon, (defender, list) => list.Any(monster => monster.IsCode(_CardId.DuelDragonToken))}, {_CardId.SeleneQueenOfTheMasterMagicians, (defender, list) => list.Any(monster => monster.HasSetcode(_Setcode.Endymion))}, - {_CardId.TheWingedDragonofRaSphereMode, (defender, list) => true} + {_CardId.TheWingedDragonofRaSphereMode, (defender, list) => true}, + {_CardId.SelettriceVaalmonica, (defender, list) => list.Any(monster => !monster.IsCode(_CardId.SelettriceVaalmonica))} }; /// @@ -1127,6 +1129,15 @@ protected bool DefaultOnBecomeTarget() _CardId.EvenlyMatched, _CardId.DivineArsenalAAZEUS_SkyThunder }; + int[] destroyAllMonsterList = + { + _CardId.DarkHole, + _CardId.InterruptedKaijuSlumber + }; + int[] destroyAllOpponentMonsterList = + { + _CardId.Raigeki + }; int[] destroyAllOpponentSpellList = { _CardId.HarpiesFeatherDuster, @@ -1135,6 +1146,8 @@ protected bool DefaultOnBecomeTarget() if (Util.ChainContainsCard(destroyAllList)) return true; if (Enemy.HasInSpellZone(destroyAllOpponentSpellList, true) && Card.Location == CardLocation.SpellZone) return true; + if (Util.ChainContainsCard(destroyAllMonsterList) && Card.Location == CardLocation.MonsterZone) return true; + if (Duel.CurrentChain.Any(c => c.Controller == 1 && c.IsCode(destroyAllOpponentMonsterList)) && Card.Location == CardLocation.MonsterZone) return true; if (lightningStormOption == 0 && Card.Location == CardLocation.MonsterZone && Card.IsAttack()) return true; if (lightningStormOption == 1 && Card.Location == CardLocation.SpellZone) return true; // TODO: ChainContainsCard(id, player) @@ -1577,7 +1590,7 @@ protected bool DefaultCheckWhetherCardIsNegated(ClientCard card) if (originId == 0) originId = card.Data.Id; return crossoutDesignatorIdList.Contains(originId) || (calledbytheGraveIdCountMap.ContainsKey(originId) && calledbytheGraveIdCountMap[originId] > 0) - || card.IsDisabled(); + || (card.IsDisabled() && ((int)card.Location & (int)CardLocation.Onfield) > 0); } protected bool DefaultCheckWhetherCardIdIsNegated(int cardId) diff --git a/libWindbot/Game/AI/Enums/Floodgate.cs b/libWindbot/Game/AI/Enums/Floodgate.cs index f3f192b..39648b7 100644 --- a/libWindbot/Game/AI/Enums/Floodgate.cs +++ b/libWindbot/Game/AI/Enums/Floodgate.cs @@ -212,6 +212,17 @@ public enum Floodgate StellarNemesisTPHON_DoomsdayStar = 93039339, SPLittleKnight = 29301450, AngelRing = 40678060, - SkullGuardianTheSilenforcingProtector = 10774240 + SkullGuardianProtectorOfTheVoicelessVoice = 10774240, + FloweringEtoileTheMelodiousMagnificat = 83793721, + EnlightenmentDragon = 46186135, + GoldPrideEradicator = 45464587, + VarudrasTheFinalBringerOfTheEndTimes = 70636044, + RagnaraikaStagSovereign = 42307760, + DrytronMeteonisAlphaDraconids = 56863746, + TheUnstoppableExodiaIncarnate = 83257450, + LightAndDarknessDragonLord = 19652159, + FiendsmithDiesIrae = 82135803, + MementomictlanTecuhtlicaCombinedConqueror = 14529511, + MadolcheQueenTiaraalaFraise = 49689480 } } diff --git a/libWindbot/Game/AI/Enums/FusionSpell.cs b/libWindbot/Game/AI/Enums/FusionSpell.cs index 199558a..472baf0 100644 --- a/libWindbot/Game/AI/Enums/FusionSpell.cs +++ b/libWindbot/Game/AI/Enums/FusionSpell.cs @@ -86,6 +86,8 @@ public enum FusionSpell FusionReproduction = 43331750, ChimeraFusion = 63136489, HarmonicSynchroFusion = 7473735, - SouloftheSupremeCelestialKing = 76840111 + SouloftheSupremeCelestialKing = 76840111, + MelodiousConcerto = 31458630, + MementotlanFusion = 66518509 } } diff --git a/libWindbot/Game/AI/Enums/InvincibleMonster.cs b/libWindbot/Game/AI/Enums/InvincibleMonster.cs index 85e6ae1..7fb5fe7 100644 --- a/libWindbot/Game/AI/Enums/InvincibleMonster.cs +++ b/libWindbot/Game/AI/Enums/InvincibleMonster.cs @@ -114,6 +114,15 @@ public enum InvincibleEnemyMonster DarkGuardian = 26746975, EnvoyOfTheWaxState = 87462901, Fluffyfluff = 85401123, - YubelDasEwigLiebeWachter = 47172959 + YubelDasEwigLiebeWachter = 47172959, + TenpaiDragonFadra = 65326118, + GolgoilTheSteelSeismicSmasher = 59369430, + TalonsOfShurilane = 74150658, + NightmareApprentice = 58143852, + MillenniumoonMaiden = 37552929, + MillenniumFiendReflection = 63947968, + HereticalPhoboscobos = 76078185, + TopHatHareTheSilhouetteMagician = 1528054, + Silhouhatte = 24440742 } } diff --git a/libWindbot/Game/AI/Enums/PreventActivationEffectInBattle.cs b/libWindbot/Game/AI/Enums/PreventActivationEffectInBattle.cs index a916f8b..6809bbc 100644 --- a/libWindbot/Game/AI/Enums/PreventActivationEffectInBattle.cs +++ b/libWindbot/Game/AI/Enums/PreventActivationEffectInBattle.cs @@ -11,10 +11,6 @@ public enum PreventActivationEffectInBattle SamuraiDestroyer = 40509732, ArmadesKeeperOfBoundaries = 88033975, NumberS39UtopiaTheLightning = 56832966, - DualAvatarEmpoweredKonGyo = 33026283, - GGolemRockHammer = 98875863, - WishDragon = 64583600, - ChaosWitch = 30327674, - FissioningMotherSpider = 34034150 + DualAvatarEmpoweredKonGyo = 33026283 } } diff --git a/libWindbot/Game/AI/Enums/ShouldBeDisabledBeforeItUseEffectMonster.cs b/libWindbot/Game/AI/Enums/ShouldBeDisabledBeforeItUseEffectMonster.cs index 0eaa629..e9c2b36 100644 --- a/libWindbot/Game/AI/Enums/ShouldBeDisabledBeforeItUseEffectMonster.cs +++ b/libWindbot/Game/AI/Enums/ShouldBeDisabledBeforeItUseEffectMonster.cs @@ -63,6 +63,10 @@ public enum ShouldBeDisabledBeforeItUseEffectMonster ThreeEyedGhost = 31464658, UrsarcticPolarStar = 62714453, BattlinBoxerPromoter = 83315222, - TGRocketSalamander = 77392987 + TGRocketSalamander = 77392987, + GGolemRockHammer = 98875863, + WishDragon = 64583600, + ChaosWitch = 30327674, + FissioningMotherSpider = 34034150 } } diff --git a/libWindbot/Game/AI/Enums/ShouldNotBeMonsterTarget.cs b/libWindbot/Game/AI/Enums/ShouldNotBeMonsterTarget.cs index 8ed6cb9..aac5a93 100644 --- a/libWindbot/Game/AI/Enums/ShouldNotBeMonsterTarget.cs +++ b/libWindbot/Game/AI/Enums/ShouldNotBeMonsterTarget.cs @@ -16,6 +16,7 @@ public enum ShouldNotBeMonsterTarget BorreloadDragon = 31833038, BorrelendDragon = 98630720, DrytronMeteonisDraconids = 69815951, - MyutantBeast = 34695290 + MyutantBeast = 34695290, + VeidosTheDragonOfEndlessDarkness = 8540986 } } diff --git a/libWindbot/Game/ClientCard.cs b/libWindbot/Game/ClientCard.cs index d9beebd..e3f9f13 100644 --- a/libWindbot/Game/ClientCard.cs +++ b/libWindbot/Game/ClientCard.cs @@ -82,8 +82,7 @@ public void SetId(int id) if (Data != null) { Name = Data.Name; - if (Data.Alias != 0) - Alias = Data.Alias; + Alias = Data.Alias; } else { Name = null; Alias = 0; @@ -387,4 +386,4 @@ public bool Equals(ClientCard card) return ReferenceEquals(this, card); } } -} \ No newline at end of file +} diff --git a/libWindbot/Game/GameAI.cs b/libWindbot/Game/GameAI.cs index 4eda971..44e3c4e 100644 --- a/libWindbot/Game/GameAI.cs +++ b/libWindbot/Game/GameAI.cs @@ -1162,6 +1162,7 @@ public BattlePhaseAction ToMainPhase2() private bool ShouldExecute(CardExecutor exec, ClientCard card, ExecutorType type, int desc = -1, int timing = -1) { + Executor.SetCard(type, card, desc, timing); if (card.Id != 0 && type == ExecutorType.Activate) { if (_activatedCards.ContainsKey(card.Id) && _activatedCards[card.Id] >= 9) @@ -1169,7 +1170,6 @@ private bool ShouldExecute(CardExecutor exec, ClientCard card, ExecutorType type if (!Executor.OnPreActivate(card)) return false; } - Executor.SetCard(type, card, desc, timing); bool result = card != null && exec.Type == type && (exec.CardId == -1 || exec.CardId == card.Id) && (exec.Func == null || exec.Func()); diff --git a/libWindbot/Game/GameBehavior.cs b/libWindbot/Game/GameBehavior.cs index 0fa8dbb..c0bdc89 100644 --- a/libWindbot/Game/GameBehavior.cs +++ b/libWindbot/Game/GameBehavior.cs @@ -1024,7 +1024,7 @@ private void InternalOnSelectCard(BinaryReader packet, Func, i card.Controller = player; } if (card == null) continue; - if (card.Id == 0) + if (card.Id == 0 || card.Location == CardLocation.Deck) card.SetId(id); cards.Add(card); } @@ -1090,7 +1090,7 @@ private void InternalOnSelectUnselectCard(BinaryReader packet, Func