diff --git a/BotWrapper/bot.conf b/BotWrapper/bot.conf index e30e48f9..8bea59a4 100644 --- a/BotWrapper/bot.conf +++ b/BotWrapper/bot.conf @@ -99,6 +99,11 @@ Name=尼亚 Deck=Altergeist Dialog=near.zh-CN 幻变骚灵卡组。 AI_LV3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020 +!尼亚-拉比林斯迷宫 +Name=尼亚 Deck=Labrynth Dialog=near.zh-CN +拉比林斯迷宫卡组。 +AI_LV3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020 + !复制梁龙-闪刀姬 Name=复制梁龙 Deck=SkyStriker Dialog=anothercopy.zh-CN 旧式闪刀姬卡组。 diff --git a/Decks/AI_Labrynth.ydk b/Decks/AI_Labrynth.ydk new file mode 100644 index 00000000..d5bcea37 --- /dev/null +++ b/Decks/AI_Labrynth.ydk @@ -0,0 +1,59 @@ +#created by ... +#main +81497285 +81497285 +2347656 +41165831 +73602965 +73602965 +75730490 +1225009 +1225009 +1225009 +37629703 +37629703 +37629703 +14558127 +14558127 +14558127 +23434538 +23434538 +23434538 +74018812 +74018812 +74018812 +2511 +2511 +2511 +49238328 +49238328 +5380979 +5380979 +6351147 +6351147 +10045474 +10045474 +10045474 +30748475 +53417695 +83326048 +92714517 +92714517 +92714517 +#extra +22850702 +22850702 +93039339 +93039339 +29479265 +93084621 +93084621 +24269961 +24269961 +24269961 +67680512 +67680512 +29301450 +71607202 +94259633 +!side diff --git a/Game/AI/Decks/DogmatikaExecutor.cs b/Game/AI/Decks/DogmatikaExecutor.cs index db5d2b6b..2e6c7b39 100644 --- a/Game/AI/Decks/DogmatikaExecutor.cs +++ b/Game/AI/Decks/DogmatikaExecutor.cs @@ -1081,7 +1081,7 @@ public override void OnNewTurn() } } - public override void OnMove(int cardId, int previousControler, int previousLocation, int currentControler, int currentLocation) + public override void OnMove(ClientCard card, int previousControler, int previousLocation, int currentControler, int currentLocation) { if (previousControler == 1 && currentLocation == (int)CardLocation.MonsterZone) { @@ -1093,7 +1093,7 @@ public override void OnMove(int cardId, int previousControler, int previousLocat } } - base.OnMove(cardId, previousControler, previousLocation, currentControler, currentLocation); + base.OnMove(card, previousControler, previousLocation, currentControler, currentLocation); } public override BattlePhaseAction OnBattle(IList attackers, IList defenders) diff --git a/Game/AI/Decks/LabrynthExecutor.cs b/Game/AI/Decks/LabrynthExecutor.cs new file mode 100644 index 00000000..9a20f747 --- /dev/null +++ b/Game/AI/Decks/LabrynthExecutor.cs @@ -0,0 +1,4368 @@ +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("Labrynth", "AI_Labrynth")] + public class LabrynthExecutor : DefaultExecutor + { + public class CardId + { + public const int LadyLabrynthOfTheSilverCastle = 81497285; + public const int LovelyLabrynthOfTheSilverCastle = 2347656; + public const int UnchainedSoulOfSharvara = 41165831; + public const int AriasTheLabrynthButler = 73602965; + public const int ArianeTheLabrynthServant = 75730490; + public const int AriannaTheLabrynthServant = 1225009; + public const int LabrynthChandraglier = 37629703; + // _CardId.AshBlossom = 14558127; + // _CardId.MaxxC = 23434538; + public const int LabrynthStovieTorbie = 74018812; + public const int LabrynthCooclock = 2511; + + public const int PotOfExtravagance = 49238328; + + public const int WelcomeLabrynth = 5380979; + public const int TransactionRollback = 6351147; + // _CardId.InfiniteImpermanence = 10045474; + public const int DestructiveDarumaKarmaCannon = 30748475; + public const int EscapeOfTheUnchained = 53417695; + // _CardId.DimensionalBarrier = 83326048; + public const int BigWelcomeLabrynth = 92714517; + + public const int ChaosAngel = 22850702; + public const int SuperStarslayerTYPHON = 93039339; + public const int UnchainedAbomination = 29479265; + public const int UnchainedSoulOfAnguish = 93084621; + public const int UnchainedSoulLordOfYama = 24269961; + public const int UnchainedSoulOfRage = 67680512; + public const int SPLittleKnight = 29301450; + public const int MuckrakerFromTheUnderworld = 71607202; + public const int RelinquishedAnima = 94259633; + + 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 LabrynthExecutor(GameAI ai, Duel duel) + : base(ai, duel) + { + // startup effect/triggered chain + AddExecutor(ExecutorType.Activate, _CardId.MaxxC, MaxxCActivate); + AddExecutor(ExecutorType.Activate, CardId.PotOfExtravagance, PotOfExtravaganceActivate); + AddExecutor(ExecutorType.Repos, CardId.LovelyLabrynthOfTheSilverCastle, ReposForLabrynth); + AddExecutor(ExecutorType.Activate, CardId.ChaosAngel, ChaosAngelActivate); + AddExecutor(ExecutorType.Activate, CardId.LovelyLabrynthOfTheSilverCastle, LovelyLabrynthOfTheSilverCastleActivate); + AddExecutor(ExecutorType.Activate, CardId.RelinquishedAnima, RelinquishedAnimaActivate); + AddExecutor(ExecutorType.Activate, CardId.AriannaTheLabrynthServant, AriannaTheLabrynthServantActivate); + AddExecutor(ExecutorType.Activate, CardId.ArianeTheLabrynthServant, ArianeTheLabrynthServantActivate); + AddExecutor(ExecutorType.Activate, CardId.LabrynthChandraglier, RecycleActivate); + AddExecutor(ExecutorType.Activate, CardId.LabrynthStovieTorbie, RecycleActivate); + AddExecutor(ExecutorType.Activate, CardId.LabrynthCooclock, RecycleActivate); + AddExecutor(ExecutorType.Activate, CardId.UnchainedSoulLordOfYama, UnchainedSoulLordOfYamaActivate); + AddExecutor(ExecutorType.Activate, CardId.WelcomeLabrynth, RecycleActivate); + AddExecutor(ExecutorType.Activate, CardId.SuperStarslayerTYPHON, SuperStarslayerTYPHONActivate); + AddExecutor(ExecutorType.Activate, CardId.UnchainedAbomination, UnchainedAbominationActivate); + + // repos + AddExecutor(ExecutorType.Repos, CardId.ArianeTheLabrynthServant, ReposForLabrynth); + AddExecutor(ExecutorType.Repos, CardId.AriannaTheLabrynthServant, ReposForLabrynth); + + // negate/chain + AddExecutor(ExecutorType.Activate, _CardId.AshBlossom, AshBlossomActivate); + AddExecutor(ExecutorType.Activate, CardId.LadyLabrynthOfTheSilverCastle, LadyLabrynthOfTheSilverCastleFieldActivate); + AddExecutor(ExecutorType.Activate, CardId.AriasTheLabrynthButler, RecycleActivate); + AddExecutor(ExecutorType.Activate, CardId.SPLittleKnight, SPLittleKnightActivate); + AddExecutor(ExecutorType.Activate, _CardId.DimensionalBarrier, DimensionalBarrierActivate); + AddExecutor(ExecutorType.Activate, _CardId.InfiniteImpermanence, InfiniteImpermanenceActivate); + + AddExecutor(ExecutorType.Activate, CardId.MuckrakerFromTheUnderworld, MuckrakerFromTheUnderworldActivate); + AddExecutor(ExecutorType.Activate, CardId.UnchainedSoulOfRage, UnchainedSoulOfRageActivate); + AddExecutor(ExecutorType.Activate, CardId.TransactionRollback, TransactionRollbackActivate); + AddExecutor(ExecutorType.Activate, CardId.DestructiveDarumaKarmaCannon, DestructiveDarumaKarmaCannonActivate); + AddExecutor(ExecutorType.Activate, CardId.EscapeOfTheUnchained, EscapeOfTheUnchainedActivate); + + // sp summon + AddExecutor(ExecutorType.Activate, CardId.LadyLabrynthOfTheSilverCastle, LadyLabrynthOfTheSilverCastleHandActivate); + AddExecutor(ExecutorType.Activate, CardId.BigWelcomeLabrynth, BigWelcomeLabrynthBecomeTargetActivate); + AddExecutor(ExecutorType.Activate, CardId.WelcomeLabrynth, WelcomeLabrynthActivate); + AddExecutor(ExecutorType.Activate, CardId.BigWelcomeLabrynth, BigWelcomeLabrynthActivate); + + // clock + AddExecutor(ExecutorType.Activate, CardId.AriasTheLabrynthButler, AriasTheLabrynthButlerActivate); + AddExecutor(ExecutorType.Activate, CardId.LabrynthCooclock, LabrynthCooclockActivate); + AddExecutor(ExecutorType.Activate, CardId.BigWelcomeLabrynth, BigWelcomeLabrynthGraveActivate); + AddExecutor(ExecutorType.Activate, CardId.UnchainedSoulOfAnguish, UnchainedSoulOfAnguishActivate); + + // summon step + AddExecutor(ExecutorType.SpellSet, SpellSetForCooClockCheck); + AddExecutor(ExecutorType.Summon, CardId.ArianeTheLabrynthServant, ArianeTheLabrynthServantForRollbackSummon); + AddExecutor(ExecutorType.Summon, CardId.AriannaTheLabrynthServant, AriannaTheLabrynthServantSummon); + AddExecutor(ExecutorType.Summon, CardId.ArianeTheLabrynthServant, ArianeTheLabrynthServantSummon); + AddExecutor(ExecutorType.Summon, LabrynthForCooClockSummon); + AddExecutor(ExecutorType.Summon, ForLinkSummon); + AddExecutor(ExecutorType.Summon, ForSynchroSummon); + AddExecutor(ExecutorType.Summon, CardId.LabrynthCooclock, ForAnimaSummon); + + // furniture set + AddExecutor(ExecutorType.Activate, CardId.LabrynthChandraglier, FurnitureSetWelcomeActivate); + AddExecutor(ExecutorType.Activate, CardId.LabrynthStovieTorbie, FurnitureSetWelcomeActivate); + + // sp summon from extra + AddExecutor(ExecutorType.SpSummon, CardId.ChaosAngel, ChaosAngelSpSummonWith2Monster); + AddExecutor(ExecutorType.SpSummon, CardId.RelinquishedAnima, RelinquishedAnimaSpSummon); + AddExecutor(ExecutorType.SpSummon, CardId.UnchainedSoulLordOfYama, UnchainedSoulLordOfYamaSpSummon); + AddExecutor(ExecutorType.SpSummon, CardId.UnchainedSoulOfAnguish, UnchainedSoulOfAnguishSpSummon); + AddExecutor(ExecutorType.SpSummon, CardId.UnchainedSoulOfRage, UnchainedSoulOfRageSpSummon); + AddExecutor(ExecutorType.SpSummon, CardId.UnchainedAbomination, UnchainedAbominationSpSummon); + AddExecutor(ExecutorType.SpSummon, CardId.SPLittleKnight, SPLittleKnightSpSummon); + AddExecutor(ExecutorType.SpSummon, CardId.ChaosAngel, ChaosAngelSpSummonWith3Monster); + AddExecutor(ExecutorType.SpSummon, CardId.MuckrakerFromTheUnderworld, MuckrakerFromTheUnderworldSpSummon); + + // hand eff + AddExecutor(ExecutorType.Activate, CardId.UnchainedSoulOfSharvara, UnchainedSoulOfSharvaraActivate); + + AddExecutor(ExecutorType.SpSummon, CardId.SuperStarslayerTYPHON, SuperStarslayerTYPHONSpSummon); + AddExecutor(ExecutorType.Repos, MonsterRepos); + AddExecutor(ExecutorType.Summon, SummonForTYPHONCheck); + AddExecutor(ExecutorType.SummonOrSet, ForBigWelcomeSummon); + AddExecutor(ExecutorType.SpellSet, SpellSetCheck); + } + + const int SetcodeTimeLord = 0x4a; + const int SetcodePhantom = 0xdb; + const int SetcodeOrcust = 0x11b; + const int SetcodeUnchained = 0x130; + const int SetcodeLabrynth = 0x17e; + const int SetcodeHorus = 0x19d; + const int hintTimingMainEnd = 0x4; + const int hintBattleStart = 0x8; + + Dictionary> DeckCountTable = new Dictionary>{ + {3, new List { CardId.AriannaTheLabrynthServant, CardId.LabrynthChandraglier, _CardId.AshBlossom, _CardId.MaxxC, + CardId.LabrynthStovieTorbie, CardId.LabrynthCooclock, _CardId.InfiniteImpermanence, CardId.BigWelcomeLabrynth }}, + {2, new List { CardId.LadyLabrynthOfTheSilverCastle, CardId.AriasTheLabrynthButler, CardId.PotOfExtravagance, CardId.WelcomeLabrynth, + CardId.TransactionRollback }}, + {1, new List { CardId.LovelyLabrynthOfTheSilverCastle, CardId.UnchainedSoulOfSharvara, CardId.ArianeTheLabrynthServant, + CardId.DestructiveDarumaKarmaCannon, CardId.EscapeOfTheUnchained, _CardId.DimensionalBarrier }} + }; + List notToNegateIdList = new List{ + 58699500, 20343502 + }; + List notToBeTrapTargetList = new List{ + 72144675, 86188410, 41589166, 11443677, 72566043, 1688285, 59071624, 6511113, 48183890, 952523, 22423493, 73639099 + }; + 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 + }; + List notToDestroySpellTrap = new List { 50005218, 6767771 }; + + Dictionary calledbytheGraveCount = new Dictionary(); + bool enemyActivateMaxxC = false; + List infiniteImpermanenceList = new List(); + bool summoned = false; + List activatedCardIdList = new List(); + List currentNegateMonsterList = new List(); + List currentDestroyCardList = new List(); + List setTrapThisTurn = new List(); + List summonThisTurn = new List(); + List enemySetThisTurn = new List(); + List escapeTargetList = new List(); + List summonInChainList = new List(); + bool cooclockAffected = false; + bool cooclockActivating = false; + bool furnitureActivating = false; + bool dimensionBarrierAnnouncing = false; + int banSpSummonExceptFiendCount = 0; + int dimensionShifterCount = 0; + int enemySpSummonFromExLastTurn = 0; + int enemySpSummonFromExThisTurn = 0; + bool enemyActivateInfiniteImpermanenceFromHand = false; + int rollbackCopyCardId = 0; + List dimensionalBarrierAnnouced = new List(); + List chainSummoningIdList = new List(3); + ClientCard bigwelcomeEscaseTarget = null; + + /// + /// 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 ClientCard GetProblematicEnemyMonster(int attack = 0, bool canBeTarget = false, bool ignoreCurrentDestroy = false, CardType selfType = 0) + { + List floodagateList = Enemy.GetMonsters().Where(c => c?.Data != null && + c.IsFloodgate() && c.IsFaceup() + && CheckCanBeTargeted(c, canBeTarget, selfType) + && (!ignoreCurrentDestroy || !currentDestroyCardList.Contains(c))).OrderByDescending(card => card.Attack).ToList(); + if (floodagateList.Count() > 0) return floodagateList[0]; + + List dangerList = Enemy.MonsterZone.Where(c => c?.Data != null && + c.IsMonsterDangerous() && c.IsFaceup() && CheckCanBeTargeted(c, canBeTarget, selfType) + && (!ignoreCurrentDestroy || !currentDestroyCardList.Contains(c))).OrderByDescending(card => card.Attack).ToList(); + if (dangerList.Count() > 0) return dangerList[0]; + + List invincibleList = Enemy.MonsterZone.Where(c => c?.Data != null && + c.IsMonsterInvincible() && c.IsFaceup() && CheckCanBeTargeted(c, canBeTarget, selfType) + && (!ignoreCurrentDestroy || !currentDestroyCardList.Contains(c))).OrderByDescending(card => card.Attack).ToList(); + if (invincibleList.Count() > 0) return invincibleList[0]; + + List equippedList = Enemy.MonsterZone.Where(c => c?.Data != null && + c.EquipCards.Count() > 0 && CheckCanBeTargeted(c, canBeTarget, selfType) + && (!ignoreCurrentDestroy || !currentDestroyCardList.Contains(c))).OrderByDescending(card => card.Attack).ToList(); + if (equippedList.Count() > 0) return equippedList[0]; + + List enemyMonsters = Enemy.GetMonsters().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)) + && CheckCanBeTargeted(target, canBeTarget, selfType) && (!ignoreCurrentDestroy || !currentDestroyCardList.Contains(target)) + ) return target; + } + } + + if (attack >= 0) + { + if (attack == 0) + attack = Util.GetBestAttack(Bot); + List betterList = Enemy.MonsterZone.GetMonsters() + .Where(card => card.GetDefensePower() >= attack && card.GetDefensePower() > 0 && card.IsAttack() && CheckCanBeTargeted(card, canBeTarget, selfType) + && (!ignoreCurrentDestroy || !currentDestroyCardList.Contains(card))).OrderByDescending(card => card.Attack).ToList(); + if (betterList.Count() > 0) return betterList[0]; + } + return null; + } + + 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 ClientCard GetBestEnemyMonster(bool onlyFaceup = false, bool canBeTarget = false, bool ignoreCurrentDestroy = false, CardType selfType = 0) + { + ClientCard card = GetProblematicEnemyMonster(0, canBeTarget, ignoreCurrentDestroy, selfType); + if (card != null) + return card; + + card = Enemy.MonsterZone.Where(c => c?.Data != null && c.HasType(CardType.Monster) && c.IsFaceup() + && CheckCanBeTargeted(c, canBeTarget, selfType) && (!ignoreCurrentDestroy || currentDestroyCardList.Contains(c))) + .OrderByDescending(c => c.Attack).FirstOrDefault(); + if (card != null) + return card; + + List monsters = Enemy.GetMonsters().Where(c => !ignoreCurrentDestroy || currentDestroyCardList.Contains(c)).ToList(); + + // after GetHighestAttackMonster, the left monsters must be face-down. + if (monsters.Count() > 0 && !onlyFaceup) + return ShuffleList(monsters)[0]; + + return null; + } + + /// + /// 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 int GetEmptyMainMonsterZoneCount() + { + int remainCount = 0; + for (int idx = 0; idx < 5; ++idx) + { + if (Bot.MonsterZone[idx] == null) remainCount++; + } + return remainCount; + } + + 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)) && enemySetThisTurn.Contains(card)).ToList())); + targetList.AddRange(ShuffleList(Enemy.GetSpells().Where(card => + (!ignoreCurrentDestroy || !currentDestroyCardList.Contains(card)) && !enemySetThisTurn.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) + && !currentNegateMonsterList.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) && !currentNegateMonsterList.Contains(chainingCard)) + { + resultList.Add(chainingCard); + } + } + + return resultList; + } + + public int GetMaterialAttack(List materials) + { + if (Util.IsTurn1OrMain2()) return 0; + int result = 0; + foreach (ClientCard material in materials) + { + if (material.IsAttack() || !summonThisTurn.Contains(material)) result += material.Attack; + } + return result; + } + + public int GetBotCurrentTotalAttack(List exceptList = null) + { + if (Util.IsTurn1OrMain2()) return 0; + int result = 0; + foreach (ClientCard monster in Bot.GetMonsters()) + { + if (exceptList != null && exceptList.Contains(monster)) continue; + if (monster.IsAttack() || !summonThisTurn.Contains(monster)) result += monster.Attack; + } + return result; + } + + public List GetCanBeUsedForLinkMaterial(bool useAdvancedMonster = false, Func exceptRule = null) + { + List materialList = Bot.GetMonsters().Where(card => { + if (card.IsFacedown() || (exceptRule != null && exceptRule(card))) return false; + if (card.IsCode(CardId.MuckrakerFromTheUnderworld) && summonThisTurn.Contains(card)) return false; + if (card.IsCode(CardId.LovelyLabrynthOfTheSilverCastle) && !card.IsDisabled() && Bot.HasInSpellZoneOrInGraveyard(CardId.BigWelcomeLabrynth)) return false; + if ((card.IsCode(CardId.ChaosAngel) || card.IsCode(CardId.LadyLabrynthOfTheSilverCastle)) + && !useAdvancedMonster && (card.IsAttack() || !summonThisTurn.Contains(card))) return false; + + return true; + }).ToList(); + materialList.Sort(CompareUsableAttack); + return materialList; + } + + public bool CheckCanDirectAttack() + { + return Enemy.GetMonsterCount() == 0 && !activatedCardIdList.Contains(CardId.SPLittleKnight) && Duel.Turn > 1 && Duel.Player == 0 && Duel.Phase < DuelPhase.Main2; + } + + /// + /// Check negated turn count of id + /// + public int CheckCalledbytheGrave(int id) + { + if (!calledbytheGraveCount.ContainsKey(id)) + { + return 0; + } + return calledbytheGraveCount[id]; + } + + 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() && notToBeTrapTargetList.Contains(card.Id)))) 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 sumResult = 0; + foreach (int id in ids) + { + sumResult += CheckRemainInDeck(id); + } + + return sumResult; + } + + /// + /// 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'll be negated + /// + /// check whether card itself is disabled. + public bool CheckWhetherNegated(bool disablecheck = true, bool toFieldCheck = false, CardType type = 0) + { + if ((Card.IsSpell() || Card.IsTrap() || (((int)type & (int)CardType.Spell) == 0) || (((int)type & (int)CardType.Trap) == 0)) && CheckSpellWillBeNegate()) + return true; + if (CheckCalledbytheGrave(Card.Id) > 0) return true; + if ((Card.IsMonster() || (((int)type & (int)CardType.Monster) == 0)) && (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.IsDisabled(); + return false; + } + + public bool CheckNumber41(ClientCard card) + { + return card != null && card.IsFaceup() && card.IsCode(CardId.Number41BagooskatheTerriblyTiredTapir) && card.IsDefense() && !card.IsDisabled(); + } + + /// + /// 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 bot is at advantage. + /// + public bool CheckAtAdvantage() + { + if (GetProblematicEnemyMonster() == null && (Duel.Player == 0 || Bot.GetMonsterCount() > 0)) return true; + return false; + } + + public bool CheckShouldNoMoreSpSummon(bool isLabrynth = true) + { + if (CheckAtAdvantage() && enemyActivateMaxxC && (Duel.Turn == 1 || Duel.Phase >= DuelPhase.Main2)) + { + if (!isLabrynth) return true; + if (cooclockAffected) + { + if (Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasSetcode(SetcodeLabrynth))) return true; + if (Duel.Player == 0 && !summoned) return true; + if (setTrapThisTurn.Count() == 0) return true; + return false; + } + return true; + } + 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; + + return true; + } + + public bool CheckChainContainEnemyMaxxC() + { + foreach (ClientCard card in Duel.CurrentChain) + { + if (card.Controller == 1 && card.IsCode(_CardId.MaxxC)) return true; + } + + return false; + } + + public bool CheckBigWelcomeCanSpSummon(int cardId) + { + return Bot.HasInHandOrInGraveyard(cardId) || CheckRemainInDeck(cardId) > 0; + } + + public int CompareUsableAttack(ClientCard cardA, ClientCard cardB) + { + if (cardA == null && cardB == null) + return 0; + if (cardA == null) + return -1; + if (cardB == null) + return 1; + int powerA = (cardA.IsDefense() && summonThisTurn.Contains(cardA)) ? 0 : cardA.Attack; + int powerB = (cardB.IsDefense() && summonThisTurn.Contains(cardB)) ? 0 : cardB.Attack; + if (powerA < powerB) + return -1; + if (powerA == powerB) + return CardContainer.CompareCardLevel(cardA, cardB); + return 1; + } + + 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 notImportantMonster = botMonsters.Where(card => !banishList.Contains(card) + && ((card.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link) && Bot.HasInExtra(card.Id)) + || CheckRemainInDeck(card.Id) > 0)).ToList(); + notImportantMonster.Sort(CardContainer.CompareCardAttack); + banishList.AddRange(notImportantMonster); + + // 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 importantMonster = botMonsters.Where(card => !banishList.Contains(card) && !card.IsCode(CardId.LovelyLabrynthOfTheSilverCastle) + && ((card.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link) && !Bot.HasInExtra(card.Id)) + || CheckRemainInDeck(card.Id) == 0)).ToList(); + importantMonster.Sort(CardContainer.CompareCardAttack); + banishList.AddRange(importantMonster); + + // lovely + List lovelyList = botMonsters.Where(card => !banishList.Contains(card) && card.IsCode(CardId.LovelyLabrynthOfTheSilverCastle)).ToList(); + lovelyList.Sort(CardContainer.CompareCardAttack); + banishList.AddRange(lovelyList); + + return Util.CheckSelectCount(banishList, cards, min, max); + } + + if (currentSolvingChain.IsCode(CardId.LadyLabrynthOfTheSilverCastle) && min == 1 && max == 1 && hint == HintMsg.Set) + { + SortedDictionary> trapCheckDict = new SortedDictionary>{ + {_CardId.DimensionalBarrier, DimensionalBarrierActivate}, + {CardId.DestructiveDarumaKarmaCannon, DestructiveDarumaKarmaCannonSetCheck}, + {_CardId.InfiniteImpermanence, InfiniteImpermanenceSetCheck} + }; + foreach (KeyValuePair> pair in trapCheckDict) + { + ClientCard target = cards.FirstOrDefault(card => card.IsCode(pair.Key)); + if (target != null && pair.Value()) + { + SelectSTPlace(null, true); + return Util.CheckSelectCount(new List { target }, cards, min, max); + } + } + + ClientCard rollback = cards.FirstOrDefault(card => card.IsCode(CardId.TransactionRollback)); + if (rollback != null) + { + bool haveUnchainSoul = false; + if (!activatedCardIdList.Contains(CardId.UnchainedSoulOfSharvara)) + { + haveUnchainSoul |= Bot.HasInHand(CardId.UnchainedSoulOfSharvara); + haveUnchainSoul |= Duel.Player == 0 && Duel.Phase <= DuelPhase.Main2 + && Bot.HasInExtra(CardId.UnchainedSoulLordOfYama) && !activatedCardIdList.Contains(CardId.UnchainedSoulLordOfYama) + && (CheckRemainInDeck(CardId.UnchainedSoulOfSharvara) > 0 || Bot.HasInGraveyard(CardId.UnchainedSoulOfSharvara)) + && Bot.GetMonsters().Where(card => card.IsFaceup() && card.HasRace(CardRace.Fiend) && card.Level <= 4).Count() >= 2; + } + bool haveAriane = false; + if (!activatedCardIdList.Contains(CardId.ArianeTheLabrynthServant) && Duel.Player == 0 && Duel.Phase <= DuelPhase.Main2) + { + haveAriane |= Bot.HasInMonstersZone(CardId.ArianeTheLabrynthServant); + haveAriane |= Bot.HasInHand(CardId.ArianeTheLabrynthServant) && !summoned; + haveAriane |= Bot.GetSpells().Any(card => card.IsFacedown() && + ( + (card.IsCode(CardId.WelcomeLabrynth) && !activatedCardIdList.Contains(CardId.WelcomeLabrynth) && (cooclockAffected || !setTrapThisTurn.Contains(card))) + || + (card.IsCode(CardId.BigWelcomeLabrynth) && !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth) && (cooclockAffected || !setTrapThisTurn.Contains(card))) + ) + ); + } + + if (haveUnchainSoul || haveAriane) + { + return Util.CheckSelectCount(new List { rollback }, cards, min, max); + } + } + + // welcome check + SortedDictionary welcomeCheck = new SortedDictionary { + {CardId.BigWelcomeLabrynth, cards.FirstOrDefault(card => card.IsCode(CardId.BigWelcomeLabrynth))}, + {CardId.WelcomeLabrynth, cards.FirstOrDefault(card => card.IsCode(CardId.WelcomeLabrynth))} + }; + List welcomeCheckIdList = new List { CardId.BigWelcomeLabrynth, CardId.WelcomeLabrynth }; + foreach (KeyValuePair checkPair in welcomeCheck) + { + if (checkPair.Value != null && !Bot.HasInHand(checkPair.Key) && !Bot.HasInGraveyard(checkPair.Key) + && !Bot.GetSpells().Any(card => card.IsCode(checkPair.Key) && card.IsFacedown())) + { + SelectSTPlace(null, true); + return Util.CheckSelectCount(new List { checkPair.Value }, cards, min, max); + } + } + if (welcomeCheck[CardId.BigWelcomeLabrynth] != null && + !Bot.HasInHand(CardId.BigWelcomeLabrynth) && !Bot.GetSpells().Any(card => card.IsCode(CardId.BigWelcomeLabrynth) && card.IsFacedown())) + { + SelectSTPlace(null, true); + return Util.CheckSelectCount(new List { welcomeCheck[CardId.BigWelcomeLabrynth] }, cards, min, max); + } + + // normal set + List checkIdList = new List{_CardId.InfiniteImpermanence, _CardId.DimensionalBarrier, CardId.DestructiveDarumaKarmaCannon, + CardId.BigWelcomeLabrynth, CardId.TransactionRollback, CardId.WelcomeLabrynth}; + foreach (int checkId in checkIdList) + { + ClientCard checkCard = cards.FirstOrDefault(card => card.IsCode(checkId)); + if (checkCard != null) + { + SelectSTPlace(null, true); + return Util.CheckSelectCount(new List { checkCard }, cards, min, max); + } + } + } + + if (currentSolvingChain.IsCode(CardId.WelcomeLabrynth)) + { + banSpSummonExceptFiendCount = 2; + } + + if (currentSolvingChain.IsCode(CardId.WelcomeLabrynth) || (currentSolvingChain.IsCode(CardId.TransactionRollback) && rollbackCopyCardId == CardId.WelcomeLabrynth)) + { + Logger.DebugWriteLine("rewrite welcome's select."); + List selection = new List(); + + ClientCard ariane = GetWelcomeOrBigWelcomeTarget(cards, CardId.ArianeTheLabrynthServant); + if (ariane != null && !summonInChainList.Any(card => card.IsCode(CardId.ArianeTheLabrynthServant))) + { + if ((Duel.Player == 0 && Duel.Phase <= DuelPhase.Main2 || Duel.Player == 1 && Duel.Phase >= DuelPhase.Main2) + && Bot.HasInHandOrInSpellZone(CardId.TransactionRollback)) + { + selection.Add(ariane); + } + } + + ClientCard arianna = GetWelcomeOrBigWelcomeTarget(cards, CardId.AriannaTheLabrynthServant); + if (arianna != null && !summonInChainList.Any(card => card.IsCode(CardId.AriannaTheLabrynthServant))) + { + bool canActivateCheck = !activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant) && !CheckWhetherNegated(true, true, CardType.Monster); + if (canActivateCheck) + { + bool checkFlag = !(!activatedCardIdList.Contains(CardId.BigWelcomeLabrynth) && + (Bot.HasInGraveyard(CardId.BigWelcomeLabrynth) || Bot.GetSpells().Any(card => card.IsFacedown() && card.IsCode(CardId.BigWelcomeLabrynth)))); + checkFlag |= !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth) + && (CheckBigWelcomeCanSpSummon(CardId.LovelyLabrynthOfTheSilverCastle) || Bot.HasInMonstersZone(CardId.LovelyLabrynthOfTheSilverCastle, true, false, true)) + && Bot.GetSpells().Any(card => card.IsFacedown() && card.IsCode(CardId.BigWelcomeLabrynth) + && (!setTrapThisTurn.Contains(card) || cooclockAffected)); + checkFlag |= !(Bot.HasInMonstersZone(CardId.LovelyLabrynthOfTheSilverCastle, true, false, true) + || CheckBigWelcomeCanSpSummon(CardId.LovelyLabrynthOfTheSilverCastle)); + if (checkFlag) + { + selection.Add(arianna); + } + } + } + + ClientCard arias = GetWelcomeOrBigWelcomeTarget(cards, CardId.AriasTheLabrynthButler); + if (arias != null && !summonInChainList.Any(card => card.IsCode(CardId.AriasTheLabrynthButler)) && !Bot.HasInHandOrHasInMonstersZone(CardId.AriasTheLabrynthButler)) + { + bool canActivateCheck = !activatedCardIdList.Contains(CardId.AriasTheLabrynthButler) && !CheckWhetherNegated(true, true, CardType.Monster); + if (canActivateCheck && Bot.HasInHand(CardId.LovelyLabrynthOfTheSilverCastle)) + { + selection.Add(arias); + } + } + + ClientCard lovely = GetWelcomeOrBigWelcomeTarget(cards, CardId.LovelyLabrynthOfTheSilverCastle); + if (lovely != null && !summonInChainList.Any(card => card.IsCode(CardId.LovelyLabrynthOfTheSilverCastle))) + { + if (Bot.HasInSpellZoneOrInGraveyard(CardId.BigWelcomeLabrynth) && !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth)) + { + selection.Add(lovely); + } + } + + ClientCard lady = GetWelcomeOrBigWelcomeTarget(cards, CardId.LadyLabrynthOfTheSilverCastle); + if (lady != null) + { + if (Bot.HasInSpellZoneOrInGraveyard(CardId.BigWelcomeLabrynth) && !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth) + && !Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasRace(CardRace.Fiend) && card.Level >= 8 && !card.HasType(CardType.Xyz | CardType.Link))) + { + selection.Add(lady); + } + } + + bool attackFlag = CheckCanDirectAttack(); + bool defenseFlag = Bot.UnderAttack && Bot.GetMonsterCount() == 0; + if (attackFlag || defenseFlag) + { + ClientCard bestPowerMonster = null; + int bestPower = -1; + foreach (ClientCard target in cards) + { + YGOSharp.OCGWrapper.NamedCard cardData = YGOSharp.OCGWrapper.NamedCard.Get(target.Id); + if (cardData != null) + { + int power = attackFlag ? cardData.Attack : Math.Max(cardData.Attack, cardData.Defense); + if (bestPowerMonster == null || power > bestPower) + { + bestPowerMonster = target; + bestPower = power; + } + } + } + if (defenseFlag || GetBotCurrentTotalAttack() < Enemy.LifePoints && GetBotCurrentTotalAttack() + bestPower >= Enemy.LifePoints) + { + ClientCard realTarget = GetWelcomeOrBigWelcomeTarget(cards, bestPowerMonster.Id); + if (realTarget != null) selection.Add(realTarget); + } + } + + List checkIdList = new List{CardId.LabrynthStovieTorbie, CardId.LabrynthChandraglier, CardId.LabrynthCooclock, CardId.AriasTheLabrynthButler}; + foreach (int checkId in checkIdList) + { + if (!Bot.HasInHandOrInMonstersZoneOrInGraveyard(checkId)) + { + ClientCard target = GetWelcomeOrBigWelcomeTarget(cards, checkId); + if (target != null) selection.Add(target); + } + } + + List fullCheckIdList = new List{ + CardId.LadyLabrynthOfTheSilverCastle, CardId.LabrynthStovieTorbie, CardId.LabrynthChandraglier, CardId.LabrynthCooclock, + CardId.AriasTheLabrynthButler, CardId.ArianeTheLabrynthServant, CardId.AriannaTheLabrynthServant + }; + foreach (int checkId in fullCheckIdList) + { + ClientCard target = GetWelcomeOrBigWelcomeTarget(cards, checkId); + if (target != null && !selection.Contains(target)) selection.Add(target); + } + + if (selection.Count() > 0) return Util.CheckSelectCount(selection, cards, min, max); + } + + bool searchFlag = currentSolvingChain.IsCode(CardId.AriannaTheLabrynthServant) && hint == HintMsg.AddToHand; + bool bigwelcomeSoving = currentSolvingChain.IsCode(CardId.BigWelcomeLabrynth) || (currentSolvingChain.IsCode(CardId.TransactionRollback) && rollbackCopyCardId == CardId.BigWelcomeLabrynth); + searchFlag |= bigwelcomeSoving && hint == HintMsg.SpSummon && Bot.GetMonsterCount() == 0; + if (searchFlag) + { + Logger.DebugWriteLine("rewrite search."); + List selection = new List(); + + List furnitureCheckIdList = new List { CardId.LabrynthStovieTorbie, CardId.LabrynthCooclock, CardId.LabrynthChandraglier }; + ClientCard bigWelcome = GetWelcomeOrBigWelcomeTarget(cards, CardId.BigWelcomeLabrynth); + ClientCard welcome = GetWelcomeOrBigWelcomeTarget(cards, CardId.WelcomeLabrynth); + ClientCard arianna = GetWelcomeOrBigWelcomeTarget(cards, CardId.AriannaTheLabrynthServant); + + // search big welcome to activate this turn + if (Duel.Player == 0 && Duel.Phase <= DuelPhase.Main2) + { + if (!summoned && !activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant) && !CheckWhetherNegated(true, true, CardType.Monster) + && CheckCalledbytheGrave(CardId.AriannaTheLabrynthServant) == 0 && arianna != null && !Bot.HasInHand(CardId.AriannaTheLabrynthServant)) + { + return Util.CheckSelectCount(new List { arianna }, cards, min, max); + } + if (!CheckShouldNoMoreSpSummon()) + { + if (bigWelcome != null && !activatedCardIdList.Contains(CardId.AriasTheLabrynthButler) + && Bot.HasInHandOrHasInMonstersZone(CardId.AriasTheLabrynthButler)) + { + return Util.CheckSelectCount(new List { bigWelcome }, cards, min, max); + } + + bool canActivateSetTrap = (cooclockAffected || Bot.HasInHand(CardId.LabrynthCooclock)) + && Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasSetcode(SetcodeLabrynth)); + if (canActivateSetTrap && !Bot.HasInHandOrInSpellZone(CardId.BigWelcomeLabrynth) && !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth)) + { + return Util.CheckSelectCount(new List { AriannaSearchWelcomeTrap(cards, CardId.BigWelcomeLabrynth) }, cards, min, max); + } + } + } + + // search cooclock/bulter to activate trap + ClientCard arias = null; + ClientCard cooclock = null; + if (!activatedCardIdList.Contains(CardId.AriasTheLabrynthButler) && CheckRemainInDeck(CardId.AriasTheLabrynthButler) > 0 + && !Bot.HasInHand(CardId.AriasTheLabrynthButler)) + { + arias = GetWelcomeOrBigWelcomeTarget(cards, CardId.AriasTheLabrynthButler); + } + if (!activatedCardIdList.Contains(CardId.LabrynthCooclock) && CheckRemainInDeck(CardId.LabrynthCooclock) > 0 + && !Bot.HasInHand(CardId.LabrynthCooclock)) + { + cooclock = GetWelcomeOrBigWelcomeTarget(cards, CardId.LabrynthCooclock); + } + if (arias != null || cooclock != null) + { + SortedDictionary> trapCheckDict = new SortedDictionary> { + {CardId.BigWelcomeLabrynth, BigWelcomeLabrynthSetCheck}, + {_CardId.DimensionalBarrier, DimensionalBarrierActivate}, + {CardId.DestructiveDarumaKarmaCannon, DestructiveDarumaKarmaCannonSetCheck}, + {CardId.WelcomeLabrynth, WelcomeLabrynthSetCheck} + }; + foreach (KeyValuePair> checkPair in trapCheckDict) + { + if (Bot.GetSpells().Any(card => card.IsFacedown() && !setTrapThisTurn.Contains(card) && card.IsCode(checkPair.Key))) continue; + if (!activatedCardIdList.Contains(checkPair.Key)) + { + if (Bot.GetSpells().Any(card => card.IsFacedown() && setTrapThisTurn.Contains(card) && card.IsCode(checkPair.Key)) + && cooclock != null) + { + return Util.CheckSelectCount(new List { cooclock }, cards, min, max); + } + else if (Bot.HasInHand(checkPair.Key)) + { + if (checkPair.Value()) + { + if (arias != null) + { + return Util.CheckSelectCount(new List { arias }, cards, min, max); + } + if (Duel.Player == 0 && Duel.Phase <= DuelPhase.Main2 && cooclock != null) + { + return Util.CheckSelectCount(new List { cooclock }, cards, min, max); + } + } + } + } + } + } + + bool lackUnimportantCost = !Bot.GetSpells().Any(card => card.IsFacedown() && card.IsCode(CardId.WelcomeLabrynth, CardId.BigWelcomeLabrynth)); + if (lackUnimportantCost) + { + List handCost = Bot.Hand.Where(card => card != Card).ToList(); + lackUnimportantCost &= handCost.Count() <= 2 && !handCost.Any(card => !card.IsCode(_CardId.MaxxC, _CardId.AshBlossom, CardId.LabrynthCooclock)); + } + if (!lackUnimportantCost && cooclock != null && bigWelcome != null) + { + foreach (int furnitureId in furnitureCheckIdList) + { + if (furnitureId == CardId.LabrynthCooclock) continue; + if (CheckCalledbytheGrave(furnitureId) == 0 && !activatedCardIdList.Contains(furnitureId) && Bot.HasInHand(furnitureId)) + { + return Util.CheckSelectCount(new List { cooclock }, cards, min, max); + } + } + } + + if (Duel.Player == 0 && Duel.Phase <= DuelPhase.Main2) + { + // search not exist furniture + if (!lackUnimportantCost) + { + foreach (int checkId in furnitureCheckIdList) + { + ClientCard furniture = GetWelcomeOrBigWelcomeTarget(cards, checkId); + if (!Bot.HasInHandOrInMonstersZoneOrInGraveyard(checkId) && furniture != null) + { + if (checkId == CardId.LabrynthCooclock) + { + if (Enemy.GetMonsterCount() > 0 && !Bot.HasInHandOrInMonstersZoneOrInGraveyard(CardId.LabrynthChandraglier)) continue; + } + return Util.CheckSelectCount(new List { furniture }, cards, min, max); + } + } + } + + // search big welcome + if (bigWelcome != null) + { + bool needSpSummonLovely = !Bot.HasInMonstersZone(CardId.LovelyLabrynthOfTheSilverCastle, true, false, true) + && !Bot.HasInHandOrInSpellZone(CardId.BigWelcomeLabrynth) && cards.Any(c => c.IsCode(CardId.LovelyLabrynthOfTheSilverCastle)); + needSpSummonLovely |= Bot.HasInMonstersZone(CardId.LovelyLabrynthOfTheSilverCastle, true, false, true) && !Bot.HasInHandOrInSpellZoneOrInGraveyard(CardId.BigWelcomeLabrynth); + if (needSpSummonLovely) + { + return Util.CheckSelectCount(new List { AriannaSearchWelcomeTrap(cards, CardId.BigWelcomeLabrynth) }, cards, min, max); + } + } + // search welcome + if (welcome != null && Bot.HasInHandOrInSpellZone(CardId.BigWelcomeLabrynth) && !Bot.HasInHandOrInSpellZone(CardId.WelcomeLabrynth)) + { + return Util.CheckSelectCount(new List { AriannaSearchWelcomeTrap(cards, CardId.WelcomeLabrynth) }, cards, min, max); + } + } + + // search big welcome/arias + if (Duel.Player == 1 && (Duel.Phase <= DuelPhase.Main1 || Duel.Phase == DuelPhase.Main2) + && !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth) && !activatedCardIdList.Contains(CardId.AriasTheLabrynthButler) + && !Bot.HasInSpellZone(CardId.BigWelcomeLabrynth)) + { + if (Bot.HasInHand(CardId.BigWelcomeLabrynth) && !Bot.HasInHandOrHasInMonstersZone(CardId.AriasTheLabrynthButler) && arias != null) + { + return Util.CheckSelectCount(new List { arias }, cards, min, max); + } + if (Bot.HasInHand(CardId.AriasTheLabrynthButler) && !Bot.HasInHandOrHasInMonstersZone(CardId.BigWelcomeLabrynth) && bigWelcome != null) + { + return Util.CheckSelectCount(new List { bigWelcome }, cards, min, max); + } + } + + // search lady + ClientCard lady = GetWelcomeOrBigWelcomeTarget(cards, CardId.LadyLabrynthOfTheSilverCastle); + bool haveTrap = Duel.Player == 0 && Bot.Hand.Any(card => card.Type == (int)CardType.Trap) && Duel.Phase <= DuelPhase.Main2; + haveTrap |= Bot.GetSpells().Any(card => card.IsFacedown() && card.Type == (int)CardType.Trap); + if (!Bot.HasInHandOrHasInMonstersZone(CardId.LadyLabrynthOfTheSilverCastle) && !activatedCardIdList.Contains(CardId.LadyLabrynthOfTheSilverCastle) + && haveTrap && lady != null) + { + return Util.CheckSelectCount(new List { lady }, cards, min, max); + } + + if (!activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant) && !CheckWhetherNegated(true, true, CardType.Monster) + && CheckCalledbytheGrave(CardId.AriannaTheLabrynthServant) == 0 && arianna != null && !Bot.HasInHand(CardId.AriannaTheLabrynthServant)) + { + return Util.CheckSelectCount(new List { arianna }, cards, min, max); + } + + // search not exist furniture + if (!lackUnimportantCost) + { + foreach (int checkId in furnitureCheckIdList) + { + ClientCard furniture = GetWelcomeOrBigWelcomeTarget(cards, checkId); + if (!Bot.HasInHandOrInMonstersZoneOrInGraveyard(checkId) && furniture != null) + { + if (checkId == CardId.LabrynthCooclock) + { + if (Enemy.GetMonsterCount() > 0 && !Bot.HasInHandOrInMonstersZoneOrInGraveyard(CardId.LabrynthChandraglier)) continue; + } + return Util.CheckSelectCount(new List { furniture }, cards, min, max); + } + } + } + + // search not exist card + List uniqueCheckIdList = new List{ + CardId.BigWelcomeLabrynth, CardId.LabrynthStovieTorbie, CardId.LabrynthCooclock, CardId.LabrynthChandraglier, + CardId.LadyLabrynthOfTheSilverCastle, CardId.AriasTheLabrynthButler, CardId.ArianeTheLabrynthServant, CardId.WelcomeLabrynth}; + foreach (int checkId in uniqueCheckIdList) + { + ClientCard targetCard = GetWelcomeOrBigWelcomeTarget(cards, checkId); + if (!Bot.HasInMonstersZone(checkId) && !Bot.HasInHandOrInSpellZone(checkId) && targetCard != null) + { + if (checkId == CardId.BigWelcomeLabrynth || checkId == CardId.WelcomeLabrynth) + { + return Util.CheckSelectCount(new List { AriannaSearchWelcomeTrap(cards, checkId) }, cards, min, max); + } + else + { + return Util.CheckSelectCount(new List { targetCard }, cards, min, max); + } + } + } + + foreach (int checkId in uniqueCheckIdList) + { + ClientCard targetCard = GetWelcomeOrBigWelcomeTarget(cards, checkId); + if (CheckRemainInDeck(checkId) > 0) + { + if (checkId == CardId.BigWelcomeLabrynth || checkId == CardId.WelcomeLabrynth) + { + return Util.CheckSelectCount(new List { AriannaSearchWelcomeTrap(cards, checkId) }, cards, min, max); + } + else + { + return Util.CheckSelectCount(new List { targetCard }, cards, min, max); + } + } + } + } + + // solved when have more than 1 monster + if (bigwelcomeSoving && hint == HintMsg.SpSummon) + { + bool activateTimingFlag = Duel.Phase > DuelPhase.Main2 || (Card.IsCode(CardId.AriasTheLabrynthButler) && (CurrentTiming & hintTimingMainEnd) > 0); + + bool needDestroyFlag = GetProblematicEnemyCardList(false).Count() > 0; + needDestroyFlag |= activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant) && activateTimingFlag; + needDestroyFlag |= Bot.UnderAttack && (Bot.BattlingMonster?.GetDefensePower() ?? 0) <= (Enemy.BattlingMonster?.GetDefensePower() ?? 0) && Duel.LastChainPlayer != 0; + needDestroyFlag |= Duel.Turn == 1 && Duel.Player == 0 && !activatedCardIdList.Contains(CardId.LovelyLabrynthOfTheSilverCastle + 1); + needDestroyFlag |= Duel.Turn == 1 && Enemy.GetMonsterCount() == 0 && Enemy.GetSpellCount() == 0 && Enemy.Hand.Count > 0 + && (CurrentTiming & hintTimingMainEnd) > 0; + + if (needDestroyFlag && cards.Any(c => c.IsCode(CardId.LovelyLabrynthOfTheSilverCastle)) + && !activatedCardIdList.Contains(CardId.LovelyLabrynthOfTheSilverCastle + 1)) + { + return Util.CheckSelectCount(new List { GetWelcomeOrBigWelcomeTarget(cards, CardId.LovelyLabrynthOfTheSilverCastle) }, cards, min, max); + } + if (cards.Any(c => c.IsCode(CardId.AriannaTheLabrynthServant)) + && !activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant) && !Bot.HasInMonstersZone(CardId.AriannaTheLabrynthServant)) + { + return Util.CheckSelectCount(new List { GetWelcomeOrBigWelcomeTarget(cards, CardId.AriannaTheLabrynthServant) }, cards, min, max); + } + if (cards.Any(c => c.IsCode(CardId.LovelyLabrynthOfTheSilverCastle)) + && !activatedCardIdList.Contains(CardId.LovelyLabrynthOfTheSilverCastle + 1)) + { + return Util.CheckSelectCount(new List { GetWelcomeOrBigWelcomeTarget(cards, CardId.LovelyLabrynthOfTheSilverCastle) }, cards, min, max); + } + if (cards.Any(c => c.IsCode(CardId.AriannaTheLabrynthServant)) + && !activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant) && !chainSummoningIdList.Contains(CardId.AriannaTheLabrynthServant)) + { + return Util.CheckSelectCount(new List { GetWelcomeOrBigWelcomeTarget(cards, CardId.AriannaTheLabrynthServant) }, cards, min, max); + } + if (cards.Any(c => c.IsCode(CardId.LadyLabrynthOfTheSilverCastle)) + && Duel.Turn > 1 && Duel.Phase < DuelPhase.Main2 && Duel.Player == 0 && Enemy.GetMonsterCount() == 0) + { + return Util.CheckSelectCount(new List { GetWelcomeOrBigWelcomeTarget(cards, CardId.LadyLabrynthOfTheSilverCastle) }, cards, min, max); + } + List furnitureCheckIdList = new List { CardId.LabrynthStovieTorbie, CardId.LabrynthCooclock, CardId.LabrynthChandraglier, CardId.AriasTheLabrynthButler }; + foreach (int furniture in furnitureCheckIdList) + { + if (cards.Any(c => c.IsCode(furniture)) && !Bot.HasInHandOrInMonstersZoneOrInGraveyard(furniture)) + { + return Util.CheckSelectCount(new List { GetWelcomeOrBigWelcomeTarget(cards, furniture) }, cards, min, max); + } + } + List checkIdList = new List{CardId.ArianeTheLabrynthServant, CardId.LadyLabrynthOfTheSilverCastle, CardId.AriannaTheLabrynthServant, + CardId.LabrynthStovieTorbie, CardId.LabrynthCooclock, CardId.LabrynthChandraglier, CardId.AriasTheLabrynthButler}; + foreach (int checkId in checkIdList) + { + if (cards.Any(c => c.IsCode(checkId))) + { + return Util.CheckSelectCount(new List { GetWelcomeOrBigWelcomeTarget(cards, checkId) }, cards, min, max); + } + } + // should not get here + Logger.DebugWriteLine("[warning] call BigWelcomeSpSummon with no select."); + } + + if (bigwelcomeSoving && hint == HintMsg.ReturnToHand) + { + if (bigwelcomeEscaseTarget != null && cards.Contains(bigwelcomeEscaseTarget)) + { + return Util.CheckSelectCount(new List { bigwelcomeEscaseTarget }, cards, min, max); + } + + ClientCard cooclock = cards.FirstOrDefault(c => c.IsCode(CardId.LabrynthCooclock)); + bool canSearchWelcome = CheckRemainInDeck(CardId.WelcomeLabrynth, CardId.BigWelcomeLabrynth) > 0 + && (Bot.HasInHandOrHasInMonstersZone(new List { CardId.LabrynthChandraglier, CardId.LabrynthStovieTorbie }) + || summonInChainList.Any(c => c.IsCode(CardId.AriannaTheLabrynthServant)) + || (Duel.Player == 0 && !summoned && !activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant) && Bot.HasInHand(CardId.AriannaTheLabrynthServant))); + if (cooclock != null) + { + if (setTrapThisTurn.Count() > 0 + || (Duel.Turn == 1 && ( + (!activatedCardIdList.Contains(CardId.LadyLabrynthOfTheSilverCastle) && Bot.HasInHandOrHasInMonstersZone(CardId.LadyLabrynthOfTheSilverCastle)) + || canSearchWelcome + ) + ) + || Duel.Turn == 0 && canSearchWelcome + ) + return Util.CheckSelectCount(new List { cooclock }, cards, min, max); + } + + ClientCard defenseLady = cards.FirstOrDefault(c => c.IsDefense() && c.IsCode(CardId.LadyLabrynthOfTheSilverCastle)); + ClientCard attackLady = cards.FirstOrDefault(c => c.IsAttack() && c.IsCode(CardId.LadyLabrynthOfTheSilverCastle)); + if (Bot.GetMonsters().Any(card => (Duel.Player == 1 || card.IsDefense()) && card.IsCode(CardId.LadyLabrynthOfTheSilverCastle)) + && (!activatedCardIdList.Contains(CardId.LadyLabrynthOfTheSilverCastle) || activatedCardIdList.Contains(CardId.LadyLabrynthOfTheSilverCastle + 1))) + { + if (defenseLady != null) return Util.CheckSelectCount(new List { defenseLady }, cards, min, max); + if (attackLady != null) return Util.CheckSelectCount(new List { attackLady }, cards, min, max); + } + if (summonInChainList.Any(c => c.IsCode(CardId.LovelyLabrynthOfTheSilverCastle))) + { + List returnCheckIdList = new List{ + _CardId.MaxxC, CardId.AriannaTheLabrynthServant, _CardId.AshBlossom, CardId.LabrynthCooclock, CardId.LadyLabrynthOfTheSilverCastle, + CardId.LabrynthChandraglier, CardId.LabrynthStovieTorbie, CardId.AriasTheLabrynthButler, CardId.UnchainedSoulOfSharvara, CardId.ArianeTheLabrynthServant + }; + foreach (int checkId in returnCheckIdList) + { + ClientCard returnTarget = cards.FirstOrDefault(c => c.IsCode(checkId)); + if (returnTarget != null) return Util.CheckSelectCount(new List { returnTarget }, cards, min, max); + } + return Util.CheckSelectCount(cards.OrderBy(card => card.Attack).ToList(), cards, min, max); + } + if (cards.Count() == 1) return Util.CheckSelectCount(cards.OrderBy(card => card.Attack).ToList(), cards, min, max); + ClientCard ariannaNotSummon = cards.FirstOrDefault(c => c.IsCode(CardId.AriannaTheLabrynthServant) && !summonInChainList.Contains(c)); + if (ariannaNotSummon != null) return Util.CheckSelectCount(new List { ariannaNotSummon }, cards, min, max); + else + { + // compare which have lower attack + ClientCard fieldTarget = Bot.GetMonsters().Where(card => !card.IsCode(CardId.LovelyLabrynthOfTheSilverCastle)) + .OrderBy(card => card.Attack).FirstOrDefault(); + if (fieldTarget != null) return Util.CheckSelectCount(new List { fieldTarget }, cards, min, max); + } + } + } + + return base.OnSelectCard(cards, min, max, hint, cancelable); + } + + public ClientCard GetWelcomeOrBigWelcomeTarget(IList cards, int cardId) + { + ClientCard graveTarget = cards.FirstOrDefault(card => card.IsCode(cardId) && card.Location == CardLocation.Grave); + if (graveTarget != null) return graveTarget; + ClientCard deckTarget = cards.FirstOrDefault(card => card.IsCode(cardId) && card.Location == CardLocation.Deck); + if (deckTarget != null) return deckTarget; + ClientCard handTarget = cards.FirstOrDefault(card => card.IsCode(cardId) && card.Location == CardLocation.Hand); + if (handTarget != null) return handTarget; + return null; + } + + public ClientCard AriannaSearchWelcomeTrap(IList cards, int welcomeId) + { + bool haveCostToSolve = Bot.HasInHand(new List { CardId.LovelyLabrynthOfTheSilverCastle, CardId.TransactionRollback, CardId.AriasTheLabrynthButler }); + if (haveCostToSolve) + { + List checkIdList = new List { CardId.LabrynthStovieTorbie, CardId.LabrynthChandraglier }; + foreach (int checkId in checkIdList) + { + ClientCard targetCard = GetWelcomeOrBigWelcomeTarget(cards, checkId); + if (targetCard != null && !Bot.HasInHandOrInMonstersZoneOrInGraveyard(checkId) && CheckCalledbytheGrave(checkId) == 0 && !activatedCardIdList.Contains(checkId)) + { + return targetCard; + } + } + foreach (int checkId in checkIdList) + { + ClientCard targetCard = GetWelcomeOrBigWelcomeTarget(cards, checkId); + if (targetCard != null && CheckCalledbytheGrave(checkId) == 0 && !activatedCardIdList.Contains(checkId)) + { + return targetCard; + } + } + } + + return GetWelcomeOrBigWelcomeTarget(cards, welcomeId); + } + + /// + /// go first + /// + public override bool OnSelectHand() + { + return true; + } + + public override bool OnSelectMonsterSummonOrSet(ClientCard card) + { + if (card.Attack > 0 && CheckCanDirectAttack()) return false; + if (card.Attack <= 1000) return true; + + return base.OnSelectMonsterSummonOrSet(card); + } + + public override int OnSelectPlace(int cardId, int player, CardLocation location, int available) + { + if (player == 0 && location == CardLocation.MonsterZone) + { + // selected in summon process + if (cardId == CardId.RelinquishedAnima) + { + return base.OnSelectPlace(cardId, player, location, available); + } + if (cardId == CardId.UnchainedSoulLordOfYama || cardId == CardId.UnchainedSoulOfAnguish) + { + if (Bot.MonsterZone[0] != null && Bot.MonsterZone[2] != null && (Zones.z6 & available) != 0) return Zones.z6; + if (Bot.MonsterZone[2] != null && Bot.MonsterZone[4] != null && (Zones.z5 & available) != 0) return Zones.z5; + } + if (cardId == CardId.MuckrakerFromTheUnderworld || cardId == CardId.UnchainedSoulOfRage) + { + if (Bot.MonsterZone[1] != null && (Zones.z6 & available) != 0) return Zones.z6; + if (Bot.MonsterZone[3] != null && (Zones.z5 & available) != 0) return Zones.z5; + } + + List zoneIdList = ShuffleList(new List { 0, 2, 4 }); + zoneIdList.AddRange(ShuffleList(new List { 1, 3 })); + zoneIdList.AddRange(ShuffleList(new List { 5, 6 })); + 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 CardPosition OnSelectPosition(int cardId, IList positions) + { + 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 int OnSelectOption(IList options) + { + // override for cooclock + if (options.Count() == 2 && options.Contains(1190) && options.Contains(1152)) + { + // 1190=Add to Hand, 1152=Special Summon + // return to hand to activate trap set this turn + bool canLink = Duel.Player == 0 && Duel.Phase <= DuelPhase.Main2; + if (!canLink && !Bot.HasInHand(CardId.LabrynthCooclock) && Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasSetcode(SetcodeLabrynth)) + && !activatedCardIdList.Contains(CardId.LabrynthCooclock) && !CheckWhetherWillbeRemoved() + && (activatedCardIdList.Contains(CardId.BigWelcomeLabrynth) || Bot.GetSpells().All(card => setTrapThisTurn.Contains(card) || !card.IsCode(CardId.BigWelcomeLabrynth))) + && setTrapThisTurn.Any(card => card.IsFacedown() && card.IsCode(CardId.BigWelcomeLabrynth, _CardId.DimensionalBarrier, _CardId.InfiniteImpermanence, CardId.DestructiveDarumaKarmaCannon))) + { + return options.IndexOf(1190); + } + if (!enemyActivateMaxxC) return options.IndexOf(1152); + if (activatedCardIdList.Contains(CardId.LabrynthCooclock)) + { + if (!CheckShouldNoMoreSpSummon()) return options.IndexOf(1152); + } + return options.IndexOf(1190); + } + + // overrride for lovely + if (options.Contains(Util.GetStringId(CardId.LovelyLabrynthOfTheSilverCastle, 3)) && options.Contains(Util.GetStringId(CardId.LovelyLabrynthOfTheSilverCastle, 4))) + { + int botWorstAttack = 0; + ClientCard botWorstMonster = Util.GetWorstBotMonster(true); + if (botWorstMonster != null) + { + botWorstAttack = botWorstMonster.Attack; + } + List targetList = GetProblematicEnemyCardList(false); + List enemyMonster = Enemy.GetMonsters().Where(card => card.IsFaceup() && !targetList.Contains(card) + && card.GetDefensePower() >= botWorstAttack && !currentDestroyCardList.Contains(card)).ToList(); + enemyMonster.Sort(CardContainer.CompareCardAttack); + enemyMonster.Reverse(); + targetList.AddRange(enemyMonster); + targetList.AddRange(ShuffleList(Enemy.GetSpells().Where(card => !currentDestroyCardList.Contains(card) && card.IsFacedown()).ToList())); + if (targetList.Count() > 0) + { + currentDestroyCardList.Add(targetList[0]); + AI.SelectCard(targetList); + return options.IndexOf(Util.GetStringId(CardId.LovelyLabrynthOfTheSilverCastle, 4)); + } + else + { + return options.IndexOf(Util.GetStringId(CardId.LovelyLabrynthOfTheSilverCastle, 3)); + } + } + + // override for dimensional barrier + if (options.IndexOf(HintMsg.RITUAL) >= 0 || options.IndexOf(HintMsg.FUSION) >= 0 || options.IndexOf(HintMsg.SYNCHRO) >= 0 + || options.IndexOf(HintMsg.XYZ) >= 0 || options.IndexOf(HintMsg.PENDULUM) >= 0) + { + Dictionary> barrierCheckDict = new Dictionary> + { + {HintMsg.RITUAL, DimensionalBarrierForRitual}, + {HintMsg.FUSION, DimensionalBarrierForFusion}, + {HintMsg.SYNCHRO, DimensionalBarrierForSynchro}, + {HintMsg.XYZ, DimensionalBarrierForXyz}, + {HintMsg.PENDULUM, DimensionalBarrierForPendulum}, + }; + dimensionBarrierAnnouncing = true; + foreach (KeyValuePair> checkPair in barrierCheckDict) + { + if (options.Contains(checkPair.Key) && checkPair.Value()) + { + dimensionBarrierAnnouncing = false; + dimensionalBarrierAnnouced.Add(checkPair.Key); + return options.IndexOf(checkPair.Key); + } + } + dimensionBarrierAnnouncing = false; + List enemyMonsterList = new List(Enemy.GetMonsters()); + enemyMonsterList.AddRange(Enemy.GetGraveyardMonsters()); + Dictionary barrierCheckSecondark = new Dictionary + { + {HintMsg.RITUAL, enemyMonsterList.Any(card => card.HasType(CardType.Ritual))}, + {HintMsg.FUSION, enemyMonsterList.Any(card => card.HasType(CardType.Fusion))}, + {HintMsg.SYNCHRO, enemyMonsterList.Any(card => card.HasType(CardType.Synchro))}, + {HintMsg.XYZ, enemyMonsterList.Any(card => card.HasType(CardType.Xyz))}, + {HintMsg.PENDULUM, enemyMonsterList.Any(card => card.HasType(CardType.Pendulum))}, + }; + foreach (KeyValuePair checkPair in barrierCheckSecondark) + { + if (options.Contains(checkPair.Key) && checkPair.Value) + { + dimensionBarrierAnnouncing = false; + dimensionalBarrierAnnouced.Add(checkPair.Key); + return options.IndexOf(checkPair.Key); + } + } + List annouceList = new List { HintMsg.XYZ, HintMsg.SYNCHRO, HintMsg.FUSION, HintMsg.PENDULUM, HintMsg.RITUAL }; + foreach (int annouce in annouceList) + { + if (options.Contains(annouce)) + { + return options.IndexOf(annouce); + } + } + } + + // override for servant + // sp summon + if (options.Contains(Util.GetStringId(CardId.AriannaTheLabrynthServant, 2)) || options.Contains(Util.GetStringId(CardId.ArianeTheLabrynthServant, 2))) + { + if (GetEmptyMainMonsterZoneCount() > chainSummoningIdList.Count()) + { + bool checkFlag = false; + if (!activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant) && Bot.HasInHand(CardId.AriannaTheLabrynthServant) + && !CheckWhetherNegated(true, true, CardType.Monster) && !chainSummoningIdList.Contains(CardId.AriannaTheLabrynthServant)) + { + checkFlag = true; + AI.SelectCard(CardId.AriannaTheLabrynthServant); + } + if (!checkFlag) + { + List checkIdList = new List { CardId.LovelyLabrynthOfTheSilverCastle, CardId.LadyLabrynthOfTheSilverCastle }; + foreach (int checkId in checkIdList) + { + if (Bot.HasInHand(checkId)) + { + checkFlag = true; + AI.SelectCard(checkId); + break; + } + } + } + if (!checkFlag && Duel.Player == 0 && Duel.Phase < DuelPhase.End) + { + List linkMaterialList = GetCanBeUsedForLinkMaterial(true, card => !card.HasRace(CardRace.Fiend)); + if (linkMaterialList.Count() + chainSummoningIdList.Count() == 2) + { + // summon less atk for link + ClientCard selected = null; + int attack = 0; + foreach (ClientCard hand in Bot.Hand) + { + YGOSharp.OCGWrapper.NamedCard cardData = YGOSharp.OCGWrapper.NamedCard.Get(hand.Id); + if (cardData == null || cardData.Race != (int)CardRace.Fiend) continue; + if (selected == null || attack > hand.Attack) + { + selected = hand; + attack = hand.Attack; + } + } + if (selected != null) + { + checkFlag = true; + AI.SelectCard(selected); + } + } + } + if (!checkFlag && CheckCanDirectAttack()) + { + // summon best attack for attack + ClientCard selected = null; + int attack = 0; + foreach (ClientCard hand in Bot.Hand) + { + YGOSharp.OCGWrapper.NamedCard cardData = YGOSharp.OCGWrapper.NamedCard.Get(hand.Id); + if (cardData == null || cardData.Race != (int)CardRace.Fiend) continue; + if (selected == null || attack < hand.Attack) + { + selected = hand; + attack = hand.Attack; + } + } + if (selected != null) + { + checkFlag = true; + AI.SelectCard(selected); + } + } + + if (checkFlag) + { + if (options.Contains(Util.GetStringId(CardId.AriannaTheLabrynthServant, 2))) return options.IndexOf(Util.GetStringId(CardId.AriannaTheLabrynthServant, 2)); + if (options.Contains(Util.GetStringId(CardId.ArianeTheLabrynthServant, 2))) return options.IndexOf(Util.GetStringId(CardId.ArianeTheLabrynthServant, 2)); + } + } + } + + // set + if (options.Contains(Util.GetStringId(CardId.AriannaTheLabrynthServant, 3)) || options.Contains(Util.GetStringId(CardId.ArianeTheLabrynthServant, 3))) + { + if (!Util.ChainContainsCard(CardId.WelcomeLabrynth) || Bot.GetSpellCountWithoutField() < 4) + { + List checkIdList = new List { CardId.BigWelcomeLabrynth, CardId.WelcomeLabrynth, _CardId.InfiniteImpermanence, _CardId.DimensionalBarrier, CardId.DestructiveDarumaKarmaCannon }; + foreach (int checkId in checkIdList) + { + if (Bot.HasInHand(checkId) && (checkId == _CardId.InfiniteImpermanence || !Bot.HasInSpellZone(checkId, faceUp:false))) + { + AI.SelectCard(checkId); + if (options.Contains(Util.GetStringId(CardId.AriannaTheLabrynthServant, 3))) return options.IndexOf(Util.GetStringId(CardId.AriannaTheLabrynthServant, 3)); + if (options.Contains(Util.GetStringId(CardId.ArianeTheLabrynthServant, 3))) return options.IndexOf(Util.GetStringId(CardId.ArianeTheLabrynthServant, 3)); + } + } + } + } + + // do nothing + if (options.Contains(Util.GetStringId(CardId.AriannaTheLabrynthServant, 4))) return options.IndexOf(Util.GetStringId(CardId.AriannaTheLabrynthServant, 4)); + if (options.Contains(Util.GetStringId(CardId.ArianeTheLabrynthServant, 4))) return options.IndexOf(Util.GetStringId(CardId.ArianeTheLabrynthServant, 4)); + + return base.OnSelectOption(options); + } + + public override bool OnSelectYesNo(int desc) + { + if (desc == 96) + { + Logger.DebugWriteLine("*** muckraker replace."); + AI.SelectCard(Bot.GetMonsters().Where(card => card.IsFaceup() && card.HasRace(CardRace.Fiend)).OrderBy(card => card.Attack).ToList()); + return true; + } + return base.OnSelectYesNo(desc); + } + + public override void OnNewTurn() + { + if (Duel.Turn <= 1) + { + calledbytheGraveCount.Clear(); + dimensionShifterCount = 0; + + enemySpSummonFromExLastTurn = 0; + enemySpSummonFromExThisTurn = 0; + banSpSummonExceptFiendCount = 0; + } + enemyActivateMaxxC = false; + enemySpSummonFromExLastTurn = enemySpSummonFromExThisTurn; + enemySpSummonFromExThisTurn = 0; + rollbackCopyCardId = 0; + + List keyList = calledbytheGraveCount.Keys.ToList(); + foreach (int dic in keyList) + { + if (calledbytheGraveCount[dic] > 1) calledbytheGraveCount[dic] -= 1; + } + if (dimensionShifterCount > 0) dimensionShifterCount--; + if (banSpSummonExceptFiendCount > 0) banSpSummonExceptFiendCount--; + infiniteImpermanenceList.Clear(); + + summoned = false; + cooclockAffected = false; + activatedCardIdList.Clear(); + setTrapThisTurn.Clear(); + summonThisTurn.Clear(); + enemySetThisTurn.Clear(); + dimensionalBarrierAnnouced.Clear(); + summonInChainList.Clear(); + } + + public override void OnChaining(int player, ClientCard card) + { + if (card == null) return; + if (chainSummoningIdList.Count() > 0) + Logger.DebugWriteLine("[Welcome] Summoning: " + string.Join(",", chainSummoningIdList) + "\n"); + + 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 && !Duel.IsCurrentSolvingChainNegated()) + { + if (currentCard.Controller == 1) + { + if (currentCard.IsCode(_CardId.MaxxC)) + enemyActivateMaxxC = true; + if (currentCard.IsCode(CardId.DimensionShifter)) + dimensionShifterCount = 2; + } + if (currentCard.Controller == 0) + { + if (currentCard.IsCode(CardId.LabrynthCooclock)) + cooclockAffected = true; + } + } + + base.OnChainSolved(chainIndex); + } + + public override void OnChainEnd() + { + rollbackCopyCardId = 0; + currentNegateMonsterList.Clear(); + currentDestroyCardList.Clear(); + escapeTargetList.Clear(); + chainSummoningIdList.Clear(); + summonInChainList.Clear(); + enemyActivateInfiniteImpermanenceFromHand = false; + for (int idx = enemySetThisTurn.Count() - 1; idx >= 0; idx --) + { + ClientCard checkTarget = enemySetThisTurn[idx]; + if (checkTarget == null || checkTarget.Location != CardLocation.SpellZone || checkTarget.HasPosition(CardPosition.FaceUp)) + { + enemySetThisTurn.RemoveAt(idx); + } + } + if (cooclockActivating) + cooclockActivating = false; + furnitureActivating = false; + dimensionBarrierAnnouncing = false; + bigwelcomeEscaseTarget = null; + base.OnChainEnd(); + } + + public override void OnMove(ClientCard card, int previousControler, int previousLocation, int currentControler, int currentLocation) + { + if (previousControler == 1) + { + if (previousLocation == (int)CardLocation.Extra && currentLocation == (int)CardLocation.MonsterZone) enemySpSummonFromExThisTurn ++; + if (card != null) + { + if (card.IsCode(_CardId.InfiniteImpermanence) && previousLocation == (int)CardLocation.Hand && currentLocation == (int)CardLocation.SpellZone) + enemyActivateInfiniteImpermanenceFromHand = true; + if (card.Location == CardLocation.SpellZone && card.HasPosition(CardPosition.FaceDown)) + enemySetThisTurn.Add(card); + } + } + if (previousControler == 0) + { + if (previousLocation == (int)CardLocation.MonsterZone && currentLocation != (int)CardLocation.MonsterZone) + { + if (summonThisTurn.Contains(card)) summonThisTurn.Remove(card); + if (summonInChainList.Contains(card)) summonInChainList.Remove(card); + } + if (previousLocation == (int)CardLocation.SpellZone && currentLocation != (int)CardLocation.SpellZone) + { + if (setTrapThisTurn.Contains(card)) setTrapThisTurn.Remove(card); + } + } + if (currentControler == 0) + { + ClientCard currentSolvingChain = Duel.GetCurrentSolvingChainCard(); + if (currentLocation == (int)CardLocation.SpellZone && (currentSolvingChain == null || !currentSolvingChain.IsCode(CardId.AriasTheLabrynthButler)) + && card != null && (card.HasType(CardType.Trap) || card.IsCode(CardId.WelcomeLabrynth, CardId.BigWelcomeLabrynth)) + ) + { + Logger.DebugWriteLine("[setTrapThisTurn]set " + card.Name ?? "UnknowCard"); + setTrapThisTurn.Add(card); + } + if (currentLocation == (int)CardLocation.MonsterZone) + { + summonThisTurn.Add(card); + if (currentSolvingChain != null) summonInChainList.Add(card); + } + if (previousLocation == (int)CardLocation.Grave && currentLocation == (int)CardLocation.Removed) + { + if (currentSolvingChain != null && currentSolvingChain.Controller == 1 && currentSolvingChain.IsCode(_CardId.CalledByTheGrave)) + { + Logger.DebugWriteLine("*** " + (card.Name ?? "UnknowCard") + " is banished by CallByTheGrave"); + calledbytheGraveCount[card.Id] = 2; + } + } + } + + base.OnMove(card, previousControler, previousLocation, currentControler, currentLocation); + } + + public override BattlePhaseAction OnBattle(IList attackers, IList defenders) + { + if (attackers.Count() > 0 && defenders.Count() > 0) + { + List sortedAttacker = attackers.OrderBy(card => card.Attack).ToList(); + 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); + } + + /// + /// 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 void ResetCooclockEffect(bool onlyCheck) + { + if (!onlyCheck && cooclockAffected && setTrapThisTurn.Contains(Card)) + { + cooclockAffected = false; + setTrapThisTurn.Remove(Card); + } + } + + + + + + public bool LadyLabrynthOfTheSilverCastleFieldActivate() + { + if (Card.Location == CardLocation.MonsterZone && (Util.GetLastChainCard() == null || !Util.GetLastChainCard().IsCode(_CardId.EvenlyMatched)) + && (!CheckWhetherNegated() || Enemy.HasInMonstersZone(CardId.LadyLabrynthOfTheSilverCastle))) + { + activatedCardIdList.Add(Card.Id + 1); + return true; + } + return false; + } + + public bool LadyLabrynthOfTheSilverCastleHandActivate() + { + if (Card.Location == CardLocation.Hand) + { + // sp summon from hand + if (CheckShouldNoMoreSpSummon(true) || Util.ChainContainsCard(_CardId.EvenlyMatched)) return false; + bool activateFlag = false; + activateFlag |= CheckChainContainEnemyMaxxC(); + if (!activateFlag && GetEmptyMainMonsterZoneCount() + chainSummoningIdList.Count() <= 0) + { + return false; + } + activateFlag |= cooclockAffected && setTrapThisTurn.Count() > 0 && !Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasSetcode(SetcodeLabrynth)); + activateFlag |= Bot.GetSpells().Any(card => card.IsFacedown() && card.HasType(CardType.Trap) && !setTrapThisTurn.Contains(card)) + && !Bot.HasInMonstersZone(Card.Id, true, faceUp: true); + activateFlag |= Duel.Player == 1 && Duel.Phase >= DuelPhase.End; + activateFlag |= setTrapThisTurn.Count() > 0 && Duel.Phase >= DuelPhase.End; + activateFlag |= Bot.UnderAttack && Bot.GetMonsterCount() == 0 && !Util.ChainContainsCard(CardId.DestructiveDarumaKarmaCannon); + // for link + if (Bot.HasInExtra(CardId.UnchainedSoulLordOfYama) && Duel.Player == 0 && Duel.Phase < DuelPhase.End) + { + // check whether need summon for material count + List materialList = GetCanBeUsedForLinkMaterial(true, card => !card.HasRace(CardRace.Fiend)); + int materialCount = materialList.Count(); + if (!activatedCardIdList.Contains(CardId.UnchainedSoulOfSharvara) && Bot.GetSpells().Any(card => card.IsFacedown()) + && (!activatedCardIdList.Contains(CardId.UnchainedSoulLordOfYama) || Bot.HasInHand(CardId.UnchainedSoulOfSharvara))) materialCount++; + if ( (materialCount == 2 || materialCount == 1 && materialList.Any(card => card.IsCode(CardId.UnchainedSoulLordOfYama))) + && Bot.HasInExtra(CardId.UnchainedSoulLordOfYama) || materialList.Any(card => card.HasSetcode(SetcodeUnchained))) + { + activateFlag |= Enemy.GetMonsterCount() > 0 && Bot.HasInExtra(CardId.UnchainedSoulOfAnguish); + activateFlag |= Bot.HasInExtra(CardId.UnchainedSoulOfRage); + } + } + + if (activateFlag) + { + activatedCardIdList.Add(Card.Id); + chainSummoningIdList.Add(Card.Id); + return true; + } + } + return false; + } + + public bool LovelyLabrynthOfTheSilverCastleActivate() + { + if (CheckWhetherNegated()) return false; + if (ActivateDescription == Util.GetStringId(CardId.LovelyLabrynthOfTheSilverCastle, 0)) + { + // set from GY + List checkIdList = new List{CardId.BigWelcomeLabrynth, _CardId.InfiniteImpermanence, _CardId.DimensionalBarrier, + CardId.DestructiveDarumaKarmaCannon, CardId.WelcomeLabrynth}; + foreach (int checkId in checkIdList) + { + if (Bot.HasInGraveyard(checkId) && !Bot.HasInHandOrInSpellZone(checkId)) + { + AI.SelectCard(checkId); + activatedCardIdList.Add(Card.Id); + return true; + } + } + foreach (int checkId in checkIdList) + { + if (Bot.HasInGraveyard(checkId)) + { + AI.SelectCard(checkId); + activatedCardIdList.Add(Card.Id); + return true; + } + } + + if (GetCanBeUsedForLinkMaterial(true, card => !card.HasRace(CardRace.Fiend)).Count() == 2 + && !activatedCardIdList.Contains(CardId.UnchainedSoulLordOfYama) + && (Bot.HasInGraveyard(CardId.UnchainedSoulOfSharvara) || CheckRemainInDeck(CardId.UnchainedSoulOfSharvara) > 0)) + { + activatedCardIdList.Add(Card.Id); + return true; + } + } + else + { + // destroy + if (Enemy.GetHandCount() == 0) + { + int botWorstAttack = 0; + ClientCard botWorstMonster = Util.GetWorstBotMonster(true); + if (botWorstMonster != null) + { + botWorstAttack = botWorstMonster.Attack; + } + List targetList = GetProblematicEnemyCardList(false); + List enemyMonster = Enemy.GetMonsters().Where(card => card.IsFaceup() && !targetList.Contains(card) + && card.GetDefensePower() >= botWorstAttack && !currentDestroyCardList.Contains(card)).ToList(); + enemyMonster.Sort(CardContainer.CompareCardAttack); + enemyMonster.Reverse(); + targetList.AddRange(enemyMonster); + targetList.AddRange(ShuffleList(Enemy.GetSpells().Where(card => !currentDestroyCardList.Contains(card)).ToList())); + + if (targetList.Count() > 0) + { + currentDestroyCardList.Add(targetList[0]); + AI.SelectCard(targetList); + AI.SelectOption(1); + } + else + { + AI.SelectOption(0); + } + } + activatedCardIdList.Add(Card.Id + 1); + return true; + } + + return false; + } + + public bool UnchainedSoulOfSharvaraActivate() + { + // search + if (Card.Location == CardLocation.Grave) + { + activatedCardIdList.Add(Card.Id + 1); + SelectSTPlace(null, false); + return true; + } + + // sp summon + if (Bot.HasInSpellZone(CardId.TransactionRollback) && GetEmptyMainMonsterZoneCount() > chainSummoningIdList.Count() + && !CheckWhetherWillbeRemoved() && !CheckShouldNoMoreSpSummon(false)) + { + AI.SelectCard(CardId.TransactionRollback); + activatedCardIdList.Add(Card.Id); + return true; + } + + // escape target + if (Duel.LastChainPlayer == 1) + { + ClientCard chainCard = Util.GetLastChainCard(); + if (chainCard != null && chainCard.IsCode(targetNegateIdList)) + { + if (Duel.LastChainTargets.Any(card => card.Controller == 0 && card.IsFaceup() && card.HasRace(CardRace.Fiend) + && Duel.CurrentChain.Any(chain => chain == card) && !card.IsCode(CardId.UnchainedSoulOfRage, CardId.UnchainedSoulOfAnguish))) + { + escapeTargetList.AddRange(Duel.LastChainTargets); + AI.SelectCard(Duel.LastChainTargets); + activatedCardIdList.Add(Card.Id); + return true; + } + } + } + + // for link + bool destroySpells = Duel.Player == 0 && GetEmptyMainMonsterZoneCount() > chainSummoningIdList.Count() && Bot.GetMonsterCount() > 0 && CurrentTiming <= 0; + if (destroySpells) + { + List materialList = GetCanBeUsedForLinkMaterial(true, card => !card.HasRace(CardRace.Fiend)); + destroySpells = CheckAtAdvantage() && !Bot.HasInMonstersZone(CardId.UnchainedSoulOfRage) + && Bot.HasInExtra(CardId.UnchainedSoulOfRage) && materialList.Count() == 1; + if (Bot.HasInExtra(CardId.UnchainedSoulOfAnguish) && !Bot.HasInMonstersZone(CardId.UnchainedSoulOfAnguish) + && !activatedCardIdList.Contains(CardId.UnchainedSoulOfAnguish) && Enemy.GetMonsters().Where(card => card.IsFaceup()).Count() > 0) + { + destroySpells |= materialList.Count() == 2; + destroySpells |= materialList.Count() == 1 && materialList.Any(card => card.HasType(CardType.Link) && card.LinkCount == 2); + } + } + // for attack + destroySpells |= CheckCanDirectAttack() && GetBotCurrentTotalAttack() < Enemy.LifePoints && GetBotCurrentTotalAttack() + 2000 >= Enemy.LifePoints + && GetEmptyMainMonsterZoneCount() > chainSummoningIdList.Count(); + // for avoid lose + destroySpells |= Duel.Player == 1 && Duel.Phase == DuelPhase.Main1 && Bot.GetMonsterCount() == 0 && (CurrentTiming & hintTimingMainEnd) != 0 + && Util.GetTotalAttackingMonsterAttack(1) >= Bot.LifePoints; + if (destroySpells) + { + List destroyIdList = new List{_CardId.InfiniteImpermanence, CardId.TransactionRollback, CardId.WelcomeLabrynth, + _CardId.DimensionalBarrier, CardId.DestructiveDarumaKarmaCannon, CardId.BigWelcomeLabrynth}; + foreach (int checkId in destroyIdList) + { + ClientCard target = Bot.GetSpells().FirstOrDefault(card => card.IsFacedown() && card.IsCode(checkId)); + if (target != null) + { + AI.SelectCard(target); + activatedCardIdList.Add(Card.Id); + return true; + } + } + } + + return false; + } + + public bool AriasTheLabrynthButlerActivate() + { + if (Card.Location != CardLocation.Grave) + { + if (Util.ChainContainsCard(new int[] { _CardId.DivineArsenalAAZEUS_SkyThunder, _CardId.EvenlyMatched, _CardId.EvilswarmExcitonKnight })) return false; + if (Duel.CurrentChain.Any(card => card.Controller == 0 && card.IsCode(CardId.AriannaTheLabrynthServant))) return false; + + // set trap to activate + SortedList> checkList = new SortedList> { + {CardId.BigWelcomeLabrynth, BigWelcomeLabrynthSetCheck}, + {CardId.WelcomeLabrynth, WelcomeLabrynthSetCheck}, + {CardId.DestructiveDarumaKarmaCannon, DestructiveDarumaKarmaCannonSetCheck}, + {_CardId.DimensionalBarrier, DimensionalBarrierActivate} + }; + foreach (KeyValuePair> pair in checkList) + { + ClientCard setTarget = Bot.Hand.FirstOrDefault(card => card.IsCode(pair.Key)); + if (setTarget != null && !activatedCardIdList.Contains(pair.Key) && pair.Value()) + { + AI.SelectOption(1); + AI.SelectCard(pair.Key); + activatedCardIdList.Add(Card.Id); + SelectSTPlace(setTarget, true); + return true; + } + } + + // special summon monster + if (Bot.HasInHand(CardId.LovelyLabrynthOfTheSilverCastle)) + { + // before main end + if (Duel.Player == 0 || (CurrentTiming & hintTimingMainEnd) != 0) + { + AI.SelectOption(0); + AI.SelectCard(CardId.LovelyLabrynthOfTheSilverCastle); + chainSummoningIdList.Add(CardId.LovelyLabrynthOfTheSilverCastle); + activatedCardIdList.Add(Card.Id); + return true; + } + } + if (Bot.HasInHand(CardId.AriannaTheLabrynthServant) && !activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant) + && !CheckWhetherNegated(true, true) && !chainSummoningIdList.Contains(CardId.AriannaTheLabrynthServant)) + { + bool searchFlag = false; + if (Duel.Player == 1) + { + searchFlag |= (CurrentTiming & hintTimingMainEnd) != 0; + searchFlag |= GetProblematicEnemyCardList(false).Count() > 0 + && (Bot.HasInMonstersZoneOrInGraveyard(CardId.LovelyLabrynthOfTheSilverCastle) || CheckRemainInDeck(CardId.LovelyLabrynthOfTheSilverCastle) > 0) + && !activatedCardIdList.Contains(CardId.LovelyLabrynthOfTheSilverCastle + 1); + } + if (Duel.Player == 0) searchFlag |= summoned && !CheckShouldNoMoreSpSummon(); + if (searchFlag) + { + AI.SelectOption(0); + AI.SelectCard(CardId.AriannaTheLabrynthServant); + chainSummoningIdList.Add(CardId.AriannaTheLabrynthServant); + activatedCardIdList.Add(Card.Id); + return true; + } + } + } + return false; + } + + public bool ArianeTheLabrynthServantSummon() + { + // for attack + if (Duel.Turn > 1 && Enemy.GetMonsterCount() == 0) + { + summoned = true; + return true; + } + // for activate effect + if (!activatedCardIdList.Contains(Card.Id) && !CheckWhetherNegated(true, true) && !CheckWhetherWillbeRemoved()) + { + bool haveCost = Bot.Hand.Any(card => card.Type == (int)CardType.Trap) || Bot.GetSpells().Any(card => card.IsFacedown() && card.Type == (int)CardType.Trap); + if (haveCost && !CheckShouldNoMoreSpSummon(true)) + { + summoned = true; + return true; + } + } + + return false; + } + public bool ArianeTheLabrynthServantForRollbackSummon() + { + if (activatedCardIdList.Contains(Card.Id)) return false; + if (Bot.HasInHandOrInSpellZone(CardId.TransactionRollback) && !CheckWhetherWillbeRemoved()) + { + summoned = true; + return true; + } + + return false; + } + public bool ArianeTheLabrynthServantActivate() + { + // special summon + if (ActivateDescription == Util.GetStringId(Card.Id, 0)) + { + bool haveRollback = Bot.HasInHandOrInSpellZone(CardId.TransactionRollback); + if (CheckWhetherNegated() && !haveRollback) return false; + if (CheckShouldNoMoreSpSummon() && !(haveRollback && Bot.Graveyard.Any(card => card.IsCode(CardId.WelcomeLabrynth, CardId.BigWelcomeLabrynth)))) return false; + int specialSummonId = 0; + // arianna + if (!activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant) && CheckRemainInDeck(CardId.AriannaTheLabrynthServant) > 0) + { + specialSummonId = CardId.AriannaTheLabrynthServant; + } + // sp summon not used furniture + if (specialSummonId == 0) + { + List checkIdList = new List{CardId.LabrynthStovieTorbie, CardId.LabrynthChandraglier, CardId.LabrynthCooclock}; + foreach (int checkId in checkIdList) + { + if (!Bot.HasInHandOrInMonstersZoneOrInGraveyard(checkId) && CheckRemainInDeck(checkId) > 0) + { + specialSummonId = checkId; + break; + } + } + } + // for attack/link + if (specialSummonId == 0) + { + List checkIdList = new List(); + if (Enemy.GetMonsterCount() == 0) checkIdList.AddRange(new List{ + CardId.AriannaTheLabrynthServant, CardId.LabrynthChandraglier, CardId.LabrynthStovieTorbie, CardId.LabrynthCooclock + }); + else checkIdList.AddRange(new List{ + CardId.LabrynthChandraglier, CardId.LabrynthStovieTorbie, CardId.LabrynthCooclock, CardId.AriannaTheLabrynthServant + }); + foreach (int checkId in checkIdList) + { + if (CheckRemainInDeck(checkId) > 0) + { + specialSummonId = checkId; + break; + } + } + } + + if (specialSummonId > 0) + { + bool costSelected = false; + if (haveRollback) + { + AI.SelectCard(CardId.TransactionRollback); + costSelected = true; + } + if (!costSelected) { + ClientCard welcome = Bot.GetSpells().FirstOrDefault(card => card.IsCode(CardId.WelcomeLabrynth)); + if (welcome != null) + { + AI.SelectCard(welcome); + costSelected = true; + } + } + List costCheckList = Bot.Hand.Where(card => card.IsFacedown() && card.Type == (int)CardType.Trap).ToList(); + costCheckList.AddRange(Bot.GetSpells().Where(card => card.IsFacedown() && card.Type == (int)CardType.Trap).ToList()); + if (!costSelected) + { + List checkIdList = new List{_CardId.InfiniteImpermanence, CardId.WelcomeLabrynth, CardId.BigWelcomeLabrynth}; + foreach (int checkId in checkIdList) + { + ClientCard dumpCard = costCheckList.FirstOrDefault(card => card.IsCode(checkId)); + if (costCheckList.Count(card => card.IsCode(checkId)) > 1 && dumpCard != null) + { + AI.SelectCard(dumpCard); + costSelected = true; + break; + } + } + } + if (!costSelected) + { + List checkIdList = new List{_CardId.InfiniteImpermanence, _CardId.DimensionalBarrier, CardId.DestructiveDarumaKarmaCannon, + CardId.WelcomeLabrynth, CardId.BigWelcomeLabrynth}; + foreach (int checkId in checkIdList) + { + ClientCard checkCard = costCheckList.FirstOrDefault(card => card.IsCode(checkId)); + if (checkCard != null) + { + AI.SelectCard(checkCard); + costSelected = true; + break; + } + } + } + } + } else { + // draw + activatedCardIdList.Add(Card.Id + 1); + return true; + } + + return false; + } + + public bool AriannaTheLabrynthServantSummon() + { + // summon for search + if (!CheckWhetherNegated(true, true) && !activatedCardIdList.Contains(Card.Id)) + { + summoned = true; + return true; + } + + // summon for attack + if (Duel.Turn > 1 && Duel.Player == 0 && Duel.Phase < DuelPhase.Main2 && Enemy.GetMonsterCount() == 0 && !Bot.HasInHand(CardId.ArianeTheLabrynthServant)) + { + summoned = true; + return true; + } + + return false; + } + public bool AriannaTheLabrynthServantActivate() + { + if (CheckWhetherNegated()) return false; + // search or draw + // search target is overrided in OnSelectCard() + activatedCardIdList.Add(Card.Id); + return true; + } + + public bool AshBlossomActivate() + { + if (CheckWhetherNegated() || !CheckLastChainShouldNegated()) return false; + if (Util.GetLastChainCard().IsCode(_CardId.MaxxC)) return false; + if (DefaultAshBlossomAndJoyousSpring()) + { + if (Util.GetLastChainCard().Location == CardLocation.MonsterZone) currentNegateMonsterList.Add(Util.GetLastChainCard()); + return true; + } + return false; + } + + public bool MaxxCActivate() + { + if (CheckWhetherNegated(true) || Duel.LastChainPlayer == 0) return false; + return DefaultMaxxC(); + } + + public bool FurnitureSetWelcomeActivate() + { + if (furnitureActivating && (Card.Location == CardLocation.Hand || !DefaultOnBecomeTarget())) return false; + if (Util.ChainContainsCard(new int[]{ _CardId.DivineArsenalAAZEUS_SkyThunder, _CardId.EvenlyMatched, _CardId.EvilswarmExcitonKnight })) return false; + + if (CheckWhetherNegated()) return false; + if (Card.Location != CardLocation.Grave) + { + bool becomeTarget = Card.Location == CardLocation.MonsterZone && DefaultOnBecomeTarget() && !escapeTargetList.Contains(Card); + bool lackUnimportantCost = Bot.GetSpells().Any(card => card.IsFacedown() && card.IsCode(CardId.WelcomeLabrynth, CardId.BigWelcomeLabrynth)); + if (lackUnimportantCost) + { + List handCost = Bot.Hand.Where(card => card != Card).ToList(); + lackUnimportantCost &= handCost.Count() <= 2 && handCost.All(card => card.IsCode(_CardId.MaxxC, _CardId.AshBlossom)); + } + bool activateFlag = becomeTarget; + // set big welcome for lovely + bool canActivateSetBigWelcomeThisTurn = CheckRemainInDeck(CardId.BigWelcomeLabrynth) > 0 && cooclockAffected && !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth) + && (Bot.HasInMonstersZone(CardId.LovelyLabrynthOfTheSilverCastle, true, false, true) || CheckBigWelcomeCanSpSummon(CardId.LovelyLabrynthOfTheSilverCastle)) + && (!Bot.GetSpells().Any(card => card.IsFacedown() && card.IsCode(CardId.BigWelcomeLabrynth) && !setTrapThisTurn.Contains(card))) + && ( + Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasSetcode(SetcodeLabrynth)) + || (Bot.HasInGraveyard(CardId.LabrynthCooclock) && !activatedCardIdList.Contains(CardId.LabrynthCooclock + 1)) + || (Bot.HasInHand(CardId.LadyLabrynthOfTheSilverCastle) && !activatedCardIdList.Contains(CardId.LadyLabrynthOfTheSilverCastle)) + ); + if (canActivateSetBigWelcomeThisTurn && ShouldSetBigWelcome()) + { + bool force = becomeTarget | GetProblematicEnemyCardList(false).Count() > 0; + ClientCard cost = FurnitureGetCost(force); + if (cost != null) + { + AI.SelectCard(cost); + AI.SelectNextCard(CardId.BigWelcomeLabrynth); + activatedCardIdList.Add(Card.Id); + furnitureActivating = true; + SelectSTPlace(null, true); + return true; + } + } + bool keepOnField = (cooclockActivating || cooclockAffected) && activatedCardIdList.Contains(CardId.LabrynthCooclock + 1) + && Card.Location == CardLocation.MonsterZone && !Bot.GetMonsters().Any(card => card.IsFaceup() && card != Card && card.HasSetcode(SetcodeLabrynth)) + && setTrapThisTurn.Count() > 0; + // normal set + activateFlag |= Duel.Phase > DuelPhase.Main2 && !lackUnimportantCost && !keepOnField; + activateFlag |= Bot.HasInGraveyard(new List { CardId.WelcomeLabrynth, CardId.BigWelcomeLabrynth }) + && Bot.HasInHand(CardId.TransactionRollback) && !activatedCardIdList.Contains(CardId.TransactionRollback); + if (Duel.CurrentChain.Any(card => card != null && card.Controller == 0 && card.IsCode(CardId.BigWelcomeLabrynth) && card.Location == CardLocation.SpellZone) + && !(Bot.GetMonsterCount() == 1 && Card.Location == CardLocation.MonsterZone)) + { + activateFlag |= !lackUnimportantCost && Bot.GetMonsters().Any(card => card != Card) && !Bot.HasInGraveyard(Card.Id) && !activatedCardIdList.Contains(Card.Id + 1); + } + // trigger cooclock to defense + activateFlag |= !Util.ChainContainPlayer(0) && Duel.Player == 1 && Bot.UnderAttack && Bot.GetMonsterCount() == 0 + && Bot.HasInGraveyard(CardId.LabrynthCooclock) && !activatedCardIdList.Contains(CardId.LabrynthCooclock + 1) + && !(Bot.HasInHand(CardId.LadyLabrynthOfTheSilverCastle) && !activatedCardIdList.Contains(CardId.LadyLabrynthOfTheSilverCastle)); + + if (activateFlag) + { + ClientCard cost = FurnitureGetCost(becomeTarget); + if (cost != null) + { + AI.SelectCard(cost); + activatedCardIdList.Add(Card.Id); + furnitureActivating = true; + bool setWelcome = Bot.GetSpells().Any(card => card.IsFacedown() && card.IsCode(CardId.BigWelcomeLabrynth)); + setWelcome |= Bot.GetMonsterCount() == 0 && !Bot.HasInHandOrInSpellZone(CardId.WelcomeLabrynth) + && (!Bot.HasInGraveyard(CardId.LabrynthCooclock) || activatedCardIdList.Contains(CardId.LabrynthCooclock + 1)) + && ((Duel.Player == 0 && Duel.Phase > DuelPhase.Main2) || !Bot.Hand.Any(card => card != Card && card.Level <= 4)); + if (setWelcome) + { + AI.SelectNextCard(CardId.WelcomeLabrynth); + } else { + AI.SelectNextCard(CardId.BigWelcomeLabrynth); + } + SelectSTPlace(null, true); + return true; + } + } + } + + return false; + } + + public ClientCard FurnitureGetCost(bool force = false, List ignoreList = null) + { + if (ignoreList == null) ignoreList = new List(); + // advance cost + List advancedCostIdList = new List{ + CardId.TransactionRollback, CardId.LovelyLabrynthOfTheSilverCastle, CardId.AriasTheLabrynthButler, CardId.LabrynthChandraglier, CardId.LabrynthStovieTorbie, + CardId.WelcomeLabrynth + }; + foreach (int checkId in advancedCostIdList) + { + ClientCard cost = Bot.Hand.FirstOrDefault(card => !ignoreList.Contains(card) && card.IsCode(checkId) && card != Card); + if (cost != null) return cost; + } + // dump cost + List canCostHand = Bot.Hand.Where(card => !ignoreList.Contains(card)).ToList(); + List appearedCode = new List(canCostHand.Count()); + foreach (ClientCard hand in canCostHand) + { + if (Duel.CurrentChain.Contains(hand)) continue; + if (appearedCode.Contains(hand.Id)) return hand; + appearedCode.Add(hand.Id); + } + List costIdList = new List{ + _CardId.InfiniteImpermanence, _CardId.DimensionalBarrier, CardId.UnchainedSoulOfSharvara, CardId.EscapeOfTheUnchained, CardId.DestructiveDarumaKarmaCannon, + CardId.LabrynthCooclock, CardId.ArianeTheLabrynthServant, CardId.WelcomeLabrynth, CardId.PotOfExtravagance, CardId.LadyLabrynthOfTheSilverCastle + }; + if (force) costIdList.AddRange(new List{CardId.AriannaTheLabrynthServant, _CardId.AshBlossom, CardId.BigWelcomeLabrynth, _CardId.MaxxC}); + foreach (int checkId in costIdList) + { + ClientCard target = canCostHand.FirstOrDefault(card => !Duel.CurrentChain.Contains(card) && card.IsCode(checkId) && !Duel.CurrentChain.Contains(card)); + if (target != null) return target; + } + foreach (int checkId in costIdList) + { + ClientCard target = canCostHand.FirstOrDefault(card => card.IsCode(checkId) && !Duel.CurrentChain.Contains(card)); + if (target != null) return target; + } + + return null; + } + + public bool ShouldSetBigWelcome(bool checkArianna = true) + { + if (CheckWhetherWillbeRemoved()) return false; + bool shouldTriggerBigWelcomeFlag = GetProblematicEnemyCardList(false).Count() > 0; + shouldTriggerBigWelcomeFlag |= Duel.Player == 1 && Duel.Phase > DuelPhase.Main2; + shouldTriggerBigWelcomeFlag |= Duel.Player == 1 && GetProblematicEnemyCardList(false).Count() == 0 && GetProblematicEnemyMonster(selfType: CardType.Monster) == null + && Enemy.Hand.Count() == 1; + if (checkArianna) shouldTriggerBigWelcomeFlag |= Duel.Player == 0 && !summoned && Bot.HasInHandOrHasInMonstersZone(CardId.AriannaTheLabrynthServant) + && !activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant); + shouldTriggerBigWelcomeFlag |= Duel.Player == 0 && Duel.Phase <= DuelPhase.Main2; + return shouldTriggerBigWelcomeFlag; + } + + public bool LabrynthCooclockActivate() + { + if (Card.Location == CardLocation.Hand) + { + bool shouldTriggerBigWelcomeFlag = false; + if (Bot.HasInMonstersZone(CardId.LovelyLabrynthOfTheSilverCastle, true, false, true) || CheckBigWelcomeCanSpSummon(CardId.LovelyLabrynthOfTheSilverCastle)) { + shouldTriggerBigWelcomeFlag |= ShouldSetBigWelcome(); + } + shouldTriggerBigWelcomeFlag &= !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth); + if (shouldTriggerBigWelcomeFlag && !Bot.GetSpells().Any(card => card.IsFacedown() && !setTrapThisTurn.Contains(card) && card.IsCode(CardId.BigWelcomeLabrynth))) + { + // whether have labrynth to trigger cooclock + bool haveBigWelcome = Duel.Player == 0 && Bot.HasInHand(CardId.BigWelcomeLabrynth) + && (Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasSetcode(SetcodeLabrynth)) || (!summoned && Bot.Hand.Any(card => card != Card && card.HasType(CardType.Monster) && card.Level <= 4 && card.HasSetcode(SetcodeLabrynth)))); + if (CheckRemainInDeck(CardId.BigWelcomeLabrynth) > 0) + { + foreach (int checkId in new List { CardId.LabrynthChandraglier, CardId.LabrynthStovieTorbie }) + { + if (activatedCardIdList.Contains(checkId) || CheckCalledbytheGrave(checkId) > 0) continue; + if (Bot.HasInHand(checkId) && Bot.Hand.Count > 2 || Bot.GetMonsters().Any(card => card.IsFaceup() && !card.IsDisabled() && card.IsCode(checkId)) && Bot.Hand.Count > 1) + { + haveBigWelcome = true; + break; + } + } + } + if (haveBigWelcome) + { + activatedCardIdList.Add(Card.Id); + cooclockActivating = true; + return true; + } + } + + bool haveLabrynth = Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasSetcode(SetcodeLabrynth)); + bool triggerFlag = Duel.Player == 1 && Duel.Phase <= DuelPhase.Main2 && setTrapThisTurn.Any(card => !activatedCardIdList.Contains(card.Id)) && haveLabrynth; + triggerFlag |= Duel.Player == 1 && activatedCardIdList.Contains(CardId.LadyLabrynthOfTheSilverCastle + 1) + && (Bot.GetSpells().Any(card => card.IsFacedown() && card.Type == (int)CardType.Trap) || Util.ChainContainsCard(CardId.LadyLabrynthOfTheSilverCastle)); + triggerFlag |= setTrapThisTurn.Any(card => card.IsFacedown() && card.IsCode(CardId.BigWelcomeLabrynth) && !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth)) && haveLabrynth; + triggerFlag |= setTrapThisTurn.Any(card => card.IsFacedown() && card.IsCode(CardId.WelcomeLabrynth) && !activatedCardIdList.Contains(CardId.WelcomeLabrynth)) && haveLabrynth; + + if (triggerFlag) + { + activatedCardIdList.Add(Card.Id); + cooclockActivating = true; + return true; + } + } + + return false; + } + + public bool RecycleActivate() + { + if (Card.Location == CardLocation.Grave) + { + if (Card.IsCode(CardId.LabrynthStovieTorbie, CardId.AriasTheLabrynthButler)) + { + if (CheckShouldNoMoreSpSummon() || GetEmptyMainMonsterZoneCount() + chainSummoningIdList.Count() <= 0) return false; + chainSummoningIdList.Add(Card.Id); + } + if (Card.IsCode(CardId.WelcomeLabrynth)) SelectSTPlace(Card, false); + activatedCardIdList.Add(Card.Id + 1); + return true; + } + + return false; + } + + public bool ForLinkSummon() + { + if (Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasSetcode(SetcodeUnchained))) return false; + if (Card.Level > 4) return false; + if (CheckShouldNoMoreSpSummon()) return false; + if (!Bot.HasInExtra(CardId.UnchainedSoulLordOfYama)) return false; + + // check whether need summon for material count + List materialList = GetCanBeUsedForLinkMaterial(true, card => !card.HasRace(CardRace.Fiend)); + int materialCount = materialList.Count(); + if (!activatedCardIdList.Contains(CardId.UnchainedSoulOfSharvara) && Bot.GetSpells().Any(card => card.IsFacedown()) + && (!activatedCardIdList.Contains(CardId.UnchainedSoulLordOfYama) || Bot.HasInHand(CardId.UnchainedSoulOfSharvara))) materialCount++; + if (materialCount != 2) + { + if (materialCount != 1 || !materialList.Any(card => card.IsCode(CardId.UnchainedSoulLordOfYama))) return false; + } + + if (!Bot.HasInExtra(CardId.UnchainedSoulLordOfYama) && !materialList.Any(card => card.HasSetcode(SetcodeUnchained))) return false; + bool needSummon = false; + needSummon |= Enemy.GetMonsterCount() > 0 && Bot.HasInExtra(CardId.UnchainedSoulOfAnguish); + needSummon |= Bot.HasInExtra(CardId.UnchainedSoulOfRage); + if (needSummon) + { + // use monster with least attack + YGOSharp.OCGWrapper.NamedCard thisCardData = YGOSharp.OCGWrapper.NamedCard.Get(Card.Id); + if (thisCardData == null) return false; + if (thisCardData.Race != (int)CardRace.Fiend) return false; + foreach (ClientCard hand in Bot.Hand) + { + YGOSharp.OCGWrapper.NamedCard compareCardData = YGOSharp.OCGWrapper.NamedCard.Get(hand.Id); + if (compareCardData == null) continue; + if (!compareCardData.HasType(CardType.Monster) || compareCardData.Level > 4) continue; + if (compareCardData.Attack < thisCardData.Attack) return false; + } + summoned = true; + return true; + } + + return false; + } + public bool ForSynchroSummon() + { + if (Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasSetcode(SetcodeUnchained))) return false; + if (!Card.IsCode(new List { CardId.LabrynthStovieTorbie, CardId.ArianeTheLabrynthServant, CardId.AriannaTheLabrynthServant })) return false; + if (CheckShouldNoMoreSpSummon()) return false; + if (!Bot.HasInExtra(CardId.ChaosAngel) || dimensionalBarrierAnnouced.Contains(HintMsg.SYNCHRO)) return false; + + bool checkFlag = GetProblematicEnemyCardList(true, selfType: CardType.Monster).Count() > 0 && !CheckWhetherNegated(true, true, CardType.Monster); + if (Card.IsCode(CardId.LabrynthStovieTorbie)) + { + if (!Bot.GetMonsters().Any(card => card.IsFaceup() && !card.HasType(CardType.Xyz | CardType.Link) + && card.Level == 8 && card.HasAttribute(CardAttribute.Light | CardAttribute.Dark))) return false; + summoned = true; + return true; + } + else + { + if (!Bot.GetMonsters().Any(card => card.IsFaceup() && !card.HasType(CardType.Xyz | CardType.Link) + && card.Level == 6 && card.HasAttribute(CardAttribute.Light | CardAttribute.Dark))) return false; + summoned = true; + return true; + } + } + public bool ForAnimaSummon() + { + if (banSpSummonExceptFiendCount > 0 || !Bot.HasInExtra(CardId.RelinquishedAnima)) return false; + if (CheckWhetherNegated() || Duel.Turn == 1) return false; + + bool checkFlag = Bot.MonsterZone[1] == null && Enemy.MonsterZone[6] != null && Enemy.MonsterZone[6].HasType(CardType.Link) && Enemy.MonsterZone[6].HasLinkMarker(CardLinkMarker.Top); + checkFlag |= Bot.MonsterZone[3] == null && Enemy.MonsterZone[5] != null && Enemy.MonsterZone[5].HasType(CardType.Link) && Enemy.MonsterZone[5].HasLinkMarker(CardLinkMarker.Top); + if (Bot.GetMonstersExtraZoneCount() == 0) checkFlag |= Enemy.MonsterZone[1] != null || Enemy.MonsterZone[3] != null; + + return checkFlag; + } + + public bool LabrynthForCooClockSummon() + { + if (!cooclockAffected) return false; + if (Card.Level > 4 || !Card.HasSetcode(SetcodeLabrynth)) return false; + bool welcomeFlag = Bot.Hand.Any(card => (card.IsCode(CardId.WelcomeLabrynth) && !activatedCardIdList.Contains(CardId.WelcomeLabrynth)) + || (card.IsCode(CardId.BigWelcomeLabrynth) && !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth))); + welcomeFlag |= Bot.GetSpells().Any(card => card.IsFacedown() && setTrapThisTurn.Contains(card) && ( + (card.IsCode(CardId.WelcomeLabrynth) && !activatedCardIdList.Contains(CardId.WelcomeLabrynth)) + || (card.IsCode(CardId.BigWelcomeLabrynth) && !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth)))); + if (welcomeFlag && !Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasSetcode(SetcodeLabrynth))) + { + // summon highest attack + int currentAttack = 0; + YGOSharp.OCGWrapper.NamedCard cardData = YGOSharp.OCGWrapper.NamedCard.Get(Card.Id); + if (cardData != null) currentAttack = cardData.Attack; + List summonList = Bot.Hand.Where(card => card.IsMonster() && card.Level <= 4 && card.HasSetcode(SetcodeLabrynth)).ToList(); + foreach (ClientCard checkCard in summonList) + { + cardData = YGOSharp.OCGWrapper.NamedCard.Get(checkCard.Id); + if (cardData != null && cardData.Attack < currentAttack) return false; + } + + return true; + } + return false; + } + + public bool ForBigWelcomeSummon() + { + if (Bot.HasInSpellZone(CardId.BigWelcomeLabrynth) && Bot.GetMonsterCount() == 0 && Card.Level <= 4) + { + summoned = true; + return true; + } + return false; + } + + public bool PotOfExtravaganceActivate() + { + if (CheckWhetherNegated()) return false; + SelectSTPlace(Card, true); + activatedCardIdList.Add(Card.Id); + AI.SelectOption(1); + return true; + } + + public bool WelcomeLabrynthActivate() + { + return WelcomeLabrynthActivateCheck(false); + } + public bool WelcomeLabrynthActivateCopy() + { + return WelcomeLabrynthActivateCheck(true); + } + public bool WelcomeLabrynthSetCheck() + { + return !CheckShouldNoMoreSpSummon() && WelcomeLabrynthActivateCheck(true, true); + } + public bool WelcomeLabrynthActivateCheck(bool onlyCheck = false, bool noSelect = false) + { + if (Card.Location == CardLocation.SpellZone || onlyCheck) + { + if (GetEmptyMainMonsterZoneCount() == 0) return false; + if (CheckShouldNoMoreSpSummon()) return false; + bool activateTimingFlag = Duel.Phase > DuelPhase.Main2 || (Card.IsCode(CardId.AriasTheLabrynthButler) && (CurrentTiming & hintTimingMainEnd) > 0); + + bool becomeTarget = Card.Location == CardLocation.SpellZone && DefaultOnBecomeTarget(); + if ((Duel.Player == 0 && Duel.Phase <= DuelPhase.Main2 || Duel.Player == 1 && activateTimingFlag) + && CheckRemainInDeck(CardId.ArianeTheLabrynthServant) > 0 && Bot.HasInHandOrInSpellZone(CardId.TransactionRollback) + && !chainSummoningIdList.Contains(CardId.ArianeTheLabrynthServant)) + { + if (!noSelect) + { + chainSummoningIdList.Add(CardId.ArianeTheLabrynthServant); + activatedCardIdList.Add(Card.Id); + } + return true; + } + bool ariannaCheck = !Bot.HasInSpellZoneOrInGraveyard(CardId.BigWelcomeLabrynth) + || !(Bot.HasInMonstersZone(CardId.LovelyLabrynthOfTheSilverCastle, true, false, true) || CheckBigWelcomeCanSpSummon(CardId.LovelyLabrynthOfTheSilverCastle)); + ariannaCheck |= Duel.Player == 1 && activateTimingFlag; + ariannaCheck |= Duel.Player == 0; + if (ariannaCheck) + { + if (CheckRemainInDeck(CardId.AriannaTheLabrynthServant) > 0 && !activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant) + && !CheckWhetherNegated(true, true, CardType.Monster) && !chainSummoningIdList.Contains(CardId.AriannaTheLabrynthServant)) + { + if (!noSelect) + { + chainSummoningIdList.Add(CardId.AriannaTheLabrynthServant); + activatedCardIdList.Add(Card.Id); + } + return true; + } + } + if (Bot.HasInSpellZoneOrInGraveyard(CardId.BigWelcomeLabrynth) && !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth)) + { + if (Bot.HasInHand(CardId.LovelyLabrynthOfTheSilverCastle) && CheckRemainInDeck(CardId.AriasTheLabrynthButler) > 0 + && !chainSummoningIdList.Contains(CardId.AriasTheLabrynthButler) && !Bot.HasInMonstersZone(CardId.AriasTheLabrynthButler, true, false, true)) + { + if (!noSelect) + { + chainSummoningIdList.Add(CardId.AriasTheLabrynthButler); + activatedCardIdList.Add(Card.Id); + } + return true; + } + } + + bool activateFlag = becomeTarget; + activateFlag |= Bot.UnderAttack && Bot.GetMonsterCount() == 0; + activateFlag |= ShouldSetBigWelcome(false); + if (activateFlag) + { + if (!noSelect) + { + if (Bot.HasInSpellZoneOrInGraveyard(CardId.BigWelcomeLabrynth) && !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth) + && CheckRemainInDeck(CardId.LovelyLabrynthOfTheSilverCastle) > 0 && !chainSummoningIdList.Contains(CardId.LovelyLabrynthOfTheSilverCastle)) + { + chainSummoningIdList.Add(CardId.LovelyLabrynthOfTheSilverCastle); + } + else if (!activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant) && CheckRemainInDeck(CardId.AriannaTheLabrynthServant) > 0 + && !CheckWhetherNegated(true, true, CardType.Monster) && !chainSummoningIdList.Contains(CardId.AriannaTheLabrynthServant)) + { + chainSummoningIdList.Add(CardId.AriannaTheLabrynthServant); + } + else if (Bot.HasInGraveyard(CardId.BigWelcomeLabrynth) && !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth) + && !Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasRace(CardRace.Fiend) && card.Level >= 8) + && CheckRemainInDeck(CardId.LadyLabrynthOfTheSilverCastle) > 0 && !chainSummoningIdList.Contains(CardId.LadyLabrynthOfTheSilverCastle)) + { + chainSummoningIdList.Add(CardId.LadyLabrynthOfTheSilverCastle); + } + else { + int selectId = 0; + List checkIdList = new List{CardId.LabrynthStovieTorbie, CardId.LabrynthChandraglier, CardId.LabrynthCooclock}; + foreach (int checkId in checkIdList) + { + if (!Bot.HasInHandOrInMonstersZoneOrInGraveyard(checkId) && CheckRemainInDeck(checkId) > 0 + && !chainSummoningIdList.Contains(checkId)) + { + selectId = checkId; + break; + } + } + List fullCheckIdList = new List{ + CardId.LadyLabrynthOfTheSilverCastle, CardId.LabrynthStovieTorbie, CardId.LabrynthChandraglier, CardId.LabrynthCooclock, + CardId.AriasTheLabrynthButler, CardId.ArianeTheLabrynthServant, CardId.AriannaTheLabrynthServant + }; + if (selectId == 0) + { + foreach (int checkId in fullCheckIdList) + { + if (CheckRemainInDeck(checkId) > 0 && !chainSummoningIdList.Contains(checkId)) + { + selectId = checkId; + break; + } + } + } + if (selectId > 0) { + chainSummoningIdList.Add(selectId); + } + } + ResetCooclockEffect(onlyCheck); + + activatedCardIdList.Add(Card.Id); + } + return true; + } + + } + + return false; + } + + public bool TransactionRollbackActivate() + { + if (Card.Location == CardLocation.Grave) + { + SortedList> checkList = new SortedList> { + {CardId.BigWelcomeLabrynth, BigWelcomeLabrynthActivateCopy}, + {_CardId.DimensionalBarrier, DimensionalBarrierActivate}, + {CardId.EscapeOfTheUnchained, EscapeOfTheUnchainedActivateCopy}, + {_CardId.InfiniteImpermanence, InfiniteImpermanenceActivateCopy}, + {CardId.WelcomeLabrynth, WelcomeLabrynthActivateCopy}, + {CardId.DestructiveDarumaKarmaCannon, DestructiveDarumaKarmaCannonActivate} + }; + foreach (KeyValuePair> pair in checkList) + { + if (Bot.HasInGraveyard(pair.Key) && pair.Value()) + { + rollbackCopyCardId = pair.Key; + AI.SelectCard(pair.Key); + return true; + } + } + } + if (Card.Location == CardLocation.SpellZone) + { + if (CheckWhetherNegated()) return false; + SortedList> checkList = new SortedList> { + {CardId.WelcomeLabrynth, WelcomeLabrynthActivateCopy}, + {_CardId.CompulsoryEvacuationDevice, DefaultCompulsoryEvacuationDevice }, + {CardId.DestructiveDarumaKarmaCannon, DestructiveDarumaKarmaCannonActivate}, + {_CardId.DimensionalBarrier, DimensionalBarrierActivate}, + {CardId.EscapeOfTheUnchained, EscapeOfTheUnchainedActivateCopy}, + {_CardId.InfiniteImpermanence, InfiniteImpermanenceActivateCopy}, + {_CardId.BreakthroughSkill, DefaultBreakthroughSkill}, + {CardId.BigWelcomeLabrynth, BigWelcomeLabrynthActivateCopy} + }; + foreach (KeyValuePair> pair in checkList) + { + if (Enemy.HasInGraveyard(pair.Key) && pair.Value()) + { + rollbackCopyCardId = pair.Key; + AI.SelectCard(pair.Key); + ResetCooclockEffect(false); + return true; + } + } + } + return false; + } + + public bool InfiniteImpermanenceActivate() + { + return InfiniteImpermanenceActivateCheck(false); + } + public bool InfiniteImpermanenceActivateCopy() + { + return InfiniteImpermanenceActivateCheck(true); + } + public bool InfiniteImpermanenceSetCheck() + { + return InfiniteImpermanenceActivateCheck(true, true); + } + public bool InfiniteImpermanenceActivateCheck(bool onlyCheck = false, bool noSelect = false) + { + if (CheckWhetherNegated()) return false; + + ClientCard LastChainCard = Util.GetLastChainCard(); + + // negate spells + if (Card.Location == CardLocation.SpellZone) + { + int thisSeq = -1; + int thatSeq = -1; + for (int i = 0; i < 5; ++i) + { + if (Bot.SpellZone[i] == Card) thisSeq = i; + if (LastChainCard != null + && LastChainCard.Controller == 1 && LastChainCard.Location == CardLocation.SpellZone && Enemy.SpellZone[i] == LastChainCard) thatSeq = i; + else if (Duel.Player == 0 && Util.GetProblematicEnemySpell() != null + && Enemy.SpellZone[i] != null && Enemy.SpellZone[i].IsFloodgate()) thatSeq = i; + } + if ( (thisSeq * thatSeq >= 0 && thisSeq + thatSeq == 4) + || Util.IsChainTarget(Card) + || (LastChainCard != null && LastChainCard.Controller == 1 && LastChainCard.IsCode(_CardId.HarpiesFeatherDuster))) + { + ClientCard target = GetProblematicEnemyMonster(canBeTarget: true, selfType: CardType.Trap); + if (!noSelect) + { + if (target != null) + { + AI.SelectCard(target); + } else { + AI.SelectCard(Enemy.GetMonsters()); + } + } + if (!onlyCheck) + { + infiniteImpermanenceList.Add(thatSeq); + if (cooclockAffected && setTrapThisTurn.Contains(Card)) + { + cooclockAffected = false; + setTrapThisTurn.Remove(Card); + } + } + return true; + } + } + + // negate monster + List shouldNegateList = GetMonsterListForTargetNegate(true, CardType.Trap); + if (shouldNegateList.Count() > 0) + { + ClientCard negateTarget = shouldNegateList[0]; + currentNegateMonsterList.Add(negateTarget); + + if (Card.Location == CardLocation.SpellZone && !onlyCheck) + { + for (int i = 0; i < 5; ++ i) + { + if (Bot.SpellZone[i] == Card) + { + infiniteImpermanenceList.Add(i); + break; + } + } + } + if (Card.Location == CardLocation.Hand) + { + SelectSTPlace(Card, true); + } + if (!noSelect) AI.SelectCard(negateTarget); + currentDestroyCardList.Add(negateTarget); + ResetCooclockEffect(onlyCheck); + return true; + } + + return false; + } + + public bool DestructiveDarumaKarmaCannonActivate() + { + return DestructiveDarumaKarmaCannonActivateCheck(false); + } + public bool DestructiveDarumaKarmaCannonSetCheck() + { + return DestructiveDarumaKarmaCannonActivateCheck(true); + } + public bool DestructiveDarumaKarmaCannonActivateCheck(bool noSelect = false) + { + bool becomeTarget = Card.Location == CardLocation.SpellZone && DefaultOnBecomeTarget(); + bool activateFlag = becomeTarget && Util.IsOneEnemyBetter(true); + bool canTriggerLovely = + (!activatedCardIdList.Contains(CardId.BigWelcomeLabrynth) && Bot.GetSpells().Any(card => card.IsFacedown() && card.IsCode(CardId.BigWelcomeLabrynth) && (!cooclockAffected || !setTrapThisTurn.Contains(card))) + || Util.ChainContainsCard(CardId.BigWelcomeLabrynth)) + && (Bot.HasInMonstersZone(CardId.LovelyLabrynthOfTheSilverCastle, true, false, true) || (CheckBigWelcomeCanSpSummon(CardId.LovelyLabrynthOfTheSilverCastle) && Bot.GetMonsterCount() > 0)) + && !activatedCardIdList.Contains(CardId.LovelyLabrynthOfTheSilverCastle + 1); + + activateFlag |= Bot.UnderAttack && (Bot.BattlingMonster?.GetDefensePower() ?? 0) <= (Enemy.BattlingMonster?.GetDefensePower() ?? 0) && !Util.ChainContainPlayer(0) && !canTriggerLovely; + activateFlag |= Duel.Phase > DuelPhase.Main1 && Duel.Phase < DuelPhase.Main2 && Bot.GetMonsterCount() == 0 && Enemy.GetMonsterCount() > 0; + activateFlag |= Enemy.HasInMonstersZone(CardId.AccesscodeTalker, true) && !Util.ChainContainPlayer(0); + int linkCount = 0; + foreach (ClientCard monster in Enemy.GetMonsters()) + { + if (monster.IsFacedown()) continue; + if (!monster.HasType(CardType.Link)) linkCount++; + else linkCount += monster.LinkCount; + } + activateFlag |= linkCount >= 6 && Util.IsOneEnemyBetter(true); + if (activateFlag) + { + if (!noSelect) + { + currentDestroyCardList.AddRange(Enemy.GetMonsters()); + escapeTargetList.AddRange(Bot.GetMonsters()); + } + return true; + } + + return false; + } + + public bool EscapeOfTheUnchainedActivate() + { + return EscapeOfTheUnchainedActivateCheck(false); + } + public bool EscapeOfTheUnchainedActivateCopy() + { + return EscapeOfTheUnchainedActivateCheck(true); + } + public bool EscapeOfTheUnchainedActivateCheck(bool onlyCheck = false, bool noSelect = false) + { + if (Card.Location == CardLocation.SpellZone || onlyCheck) + { + // select targeted unchained + ClientCard selfTarget = Bot.GetMonsters().FirstOrDefault(card => card.IsFaceup() && card.HasSetcode(SetcodeUnchained) + && Duel.ChainTargets.Contains(card) && !escapeTargetList.Contains(card)); + if (selfTarget == null) + { + selfTarget = Bot.GetMonsters().Where(card => card.IsFaceup() && card.HasSetcode(SetcodeUnchained)) + .OrderBy(card => card.Attack).FirstOrDefault(); + } + if (selfTarget == null) return false; + // destroy danger card + List dangerList = GetProblematicEnemyCardList(true, selfType: CardType.Trap); + if (dangerList.Count() > 0 && Duel.LastChainPlayer != 0) + { + if (!noSelect) + { + AI.SelectCard(selfTarget); + AI.SelectNextCard(dangerList); + escapeTargetList.Add(selfTarget); + currentDestroyCardList.Add(dangerList[0]); + activatedCardIdList.Add(Card.Id); + } + return true; + } + + // best monster + int botBestPower = Util.GetBestPower(Bot); + if (Duel.Player == 1 && Duel.Phase > DuelPhase.Main1 && Duel.Phase < DuelPhase.Main2) + { + List dangerMonsters = Enemy.GetMonsters().Where(card => card.IsFaceup() && card.Attack >= botBestPower + && !currentDestroyCardList.Contains(card) && !card.IsShouldNotBeTarget() && !card.IsShouldNotBeSpellTrapTarget()) + .OrderByDescending(card => card.Attack).ToList(); + if (dangerMonsters.Count() > 0) + { + if (!noSelect) + { + AI.SelectCard(selfTarget); + AI.SelectNextCard(dangerMonsters); + escapeTargetList.Add(selfTarget); + currentDestroyCardList.Add(dangerMonsters[0]); + activatedCardIdList.Add(Card.Id); + } + return true; + } + } + + // end phase + bool activateFlag = Duel.Player == 1 && Duel.Phase > DuelPhase.Main2 + && ((Bot.HasInGraveyard(CardId.UnchainedSoulLordOfYama) && !activatedCardIdList.Contains(CardId.UnchainedSoulLordOfYama + 1)) + || (Bot.HasInMonstersZone(CardId.LovelyLabrynthOfTheSilverCastle, true, false, true) && !activatedCardIdList.Contains(CardId.LovelyLabrynthOfTheSilverCastle + 1))); + activateFlag |= DefaultOnBecomeTarget() && Card.Location == CardLocation.SpellZone && !Util.ChainContainsCard(_CardId.EvenlyMatched); + if (activateFlag) + { + List destroyTarget = GetNormalEnemyTargetList(true, true, CardType.Trap); + if (destroyTarget.Count() > 0) + { + if (!noSelect) + { + AI.SelectCard(selfTarget); + AI.SelectNextCard(destroyTarget); + escapeTargetList.Add(selfTarget); + currentDestroyCardList.Add(destroyTarget[0]); + activatedCardIdList.Add(Card.Id); + } + return true; + } + } + + } else { + if (!noSelect) + { + AI.SelectCard(CardId.UnchainedSoulOfSharvara); + activatedCardIdList.Add(Card.Id + 1); + } + return true; + } + + return false; + } + + public bool DimensionalBarrierActivate() + { + if (Duel.Player == 0 && Duel.Turn == 1) return false; + if (CheckWhetherNegated()) return false; + Dictionary> checkDict = new Dictionary> + { + {HintMsg.RITUAL, DimensionalBarrierForRitual}, + {HintMsg.FUSION, DimensionalBarrierForFusion}, + {HintMsg.SYNCHRO, DimensionalBarrierForSynchro}, + {HintMsg.XYZ, DimensionalBarrierForXyz}, + {HintMsg.PENDULUM, DimensionalBarrierForPendulum}, + }; + foreach (KeyValuePair> checkType in checkDict) + { + if (dimensionalBarrierAnnouced.Contains(checkType.Key)) continue; + if (checkType.Value()) { + ResetCooclockEffect(false); + return true; + } + } + + return DefaultOnBecomeTarget(); + } + public bool DimensionalBarrierForRitual() + { + foreach (ClientCard chainCard in Duel.CurrentChain) + { + if (chainCard != null && chainCard.Controller == 1 && !chainCard.IsDisabled() && chainCard.HasType(CardType.Ritual) + && (chainCard.HasType(CardType.Spell) || (chainCard.Location == CardLocation.MonsterZone && !currentNegateMonsterList.Contains(chainCard)))) + { + if (dimensionBarrierAnnouncing) currentNegateMonsterList.Add(chainCard); + return true; + } + } + + return false; + } + public bool DimensionalBarrierForFusion() + { + foreach (ClientCard chainCard in Duel.CurrentChain) + { + if (chainCard != null && chainCard.Controller == 1 && !chainCard.IsDisabled() && (chainCard.IsFusionSpell() + || (chainCard.HasType(CardType.Fusion) && chainCard.Location == CardLocation.MonsterZone && !currentNegateMonsterList.Contains(chainCard)))) + { + if (dimensionBarrierAnnouncing) currentNegateMonsterList.Add(chainCard); + return true; + } + } + + return false; + } + public bool DimensionalBarrierForSynchro() + { + foreach (ClientCard chainCard in Duel.CurrentChain) + { + if (chainCard != null && chainCard.Controller == 1 && !chainCard.IsDisabled() + && chainCard.HasType(CardType.Synchro) && chainCard.Location == CardLocation.MonsterZone && !currentNegateMonsterList.Contains(chainCard)) + { + if (dimensionBarrierAnnouncing) currentNegateMonsterList.Add(chainCard); + return true; + } + } + if (Duel.Player == 1 && !Util.ChainContainsCard(CardId.DestructiveDarumaKarmaCannon) && Enemy.ExtraDeck.Count() > 0) + { + bool tunerCheck = false; + bool nontunerCheck = false; + foreach (ClientCard monster in Enemy.GetMonsters()) + { + if (monster.IsFacedown() || monster.HasType(CardType.Xyz | CardType.Link)) continue; + if (monster.HasType(CardType.Tuner)) tunerCheck = true; + else nontunerCheck = true; + } + if (tunerCheck && nontunerCheck) return true; + } + + return false; + } + public bool DimensionalBarrierForXyz() + { + foreach (ClientCard chainCard in Duel.CurrentChain) + { + if (chainCard != null && chainCard.Controller == 1 && !chainCard.IsDisabled() + && chainCard.HasType(CardType.Xyz) && chainCard.Location == CardLocation.MonsterZone && !currentNegateMonsterList.Contains(chainCard)) + { + if (dimensionBarrierAnnouncing) currentNegateMonsterList.Add(chainCard); + return true; + } + } + if (Duel.Player == 1 && !Util.ChainContainsCard(CardId.DestructiveDarumaKarmaCannon) && Enemy.ExtraDeck.Count() > 0) + { + List existsLevel = new List(6); + foreach (ClientCard monster in Enemy.GetMonsters()) + { + if (monster.IsFacedown()) continue; + if (monster.IsOneForXyz()) return true; + if (monster.HasType(CardType.Xyz | CardType.Token)) continue; + int level = monster.Level; + if (level != 2 && monster.HasType(CardType.Link)) continue; + if (existsLevel.Contains(level)) return true; + existsLevel.Add(level); + } + } + + return false; + } + public bool DimensionalBarrierForPendulum() + { + foreach (ClientCard chainCard in Duel.CurrentChain) + { + if (chainCard != null && chainCard.Controller == 1 && !chainCard.IsDisabled() + && chainCard.HasType(CardType.Pendulum) && chainCard.Location == CardLocation.MonsterZone && !currentNegateMonsterList.Contains(chainCard)) + { + if (dimensionBarrierAnnouncing) currentNegateMonsterList.Add(chainCard); + return true; + } + } + + ClientCard l = Enemy.SpellZone[6]; + ClientCard r = Enemy.SpellZone[7]; + if (l != null && r != null && l.LScale != r.RScale) return true; + + return false; + } + + public bool BigWelcomeLabrynthActivate() + { + return BigWelcomeLabrynthActivateCheck(false); + } + public bool BigWelcomeLabrynthBecomeTargetActivate() + { + if (DefaultOnBecomeTarget()) return BigWelcomeLabrynthActivateCheck(false); + return false; + } + public bool BigWelcomeLabrynthActivateCopy() + { + return BigWelcomeLabrynthActivateCheck(true); + } + public bool BigWelcomeLabrynthSetCheck() + { + return !CheckShouldNoMoreSpSummon() && BigWelcomeLabrynthActivateCheck(true, true); + } + public bool BigWelcomeLabrynthActivateCheck(bool onlyCheck = false, bool noSelect = false) + { + if (CheckWhetherNegated()) return false; + if (Card.Location != CardLocation.SpellZone && !onlyCheck) return false; + if (GetEmptyMainMonsterZoneCount() == 0) return false; + bool activateTimingFlag = Duel.Phase > DuelPhase.Main2 || (Card.IsCode(CardId.AriasTheLabrynthButler) && (CurrentTiming & hintTimingMainEnd) > 0); + + bool needDestroyFlag = GetProblematicEnemyCardList(false).Count() > 0; + needDestroyFlag |= activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant) && activateTimingFlag; + needDestroyFlag |= Bot.UnderAttack && (Bot.BattlingMonster?.GetDefensePower() ?? 0) <= (Enemy.BattlingMonster?.GetDefensePower() ?? 0) && Duel.LastChainPlayer != 0; + needDestroyFlag |= Duel.Turn == 1 && Duel.Player == 0 && !activatedCardIdList.Contains(CardId.LovelyLabrynthOfTheSilverCastle + 1); + needDestroyFlag |= Duel.Turn == 1 && Enemy.GetMonsterCount() == 0 && Enemy.GetSpellCount() == 0 && Enemy.Hand.Count > 0 + && (CurrentTiming & hintTimingMainEnd) > 0; + + // do not activate when welcome is activating + bool haveEnemyChain = false; + bool haveWelcome = false; + foreach (ClientCard chain in Duel.CurrentChain) + { + if (chain != null) + { + if (chain.Controller == 1) + { + haveEnemyChain = true; + break; + } + if (chain.IsCode(CardId.WelcomeLabrynth, CardId.TransactionRollback, CardId.LadyLabrynthOfTheSilverCastle)) haveWelcome = true; + } + } + if (haveWelcome && !haveEnemyChain) return false; + + // escape target + List targetList = Bot.GetMonsters(); + foreach (ClientCard target in targetList) + { + if (Duel.ChainTargets.Contains(target) && !escapeTargetList.Contains(target) + && !(target.IsCode(CardId.UnchainedSoulOfRage, CardId.UnchainedSoulOfAnguish) && Duel.CurrentChain.Contains(target))) + { + Logger.DebugWriteLine("[BigWelcome]escape target"); + if (!noSelect) + { + bigwelcomeEscaseTarget = target; + escapeTargetList.Add(target); + activatedCardIdList.Add(Card.Id); + } + return true; + } + } + + if (Bot.GetMonsterCount() > 0) + { + bool flag1 = needDestroyFlag && !activatedCardIdList.Contains(CardId.LovelyLabrynthOfTheSilverCastle + 1) && (Util.ChainContainPlayer(1) || Duel.LastChainPlayer != 0); + bool flag2 = DefaultOnBecomeTarget(); + bool flag3 = Duel.Player == 1 && !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth) && activateTimingFlag; + bool flag4 = Duel.Player == 0 && Duel.LastChainPlayer != 0 && !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth); + Logger.DebugWriteLine("[BigWelcome count>0]flag: "+ flag1 + " " + flag2 + " " + flag3 + " " + flag4); + needDestroyFlag |= flag3; + if (flag1 || flag2 || flag3 || flag4) + { + bool spSummonLovely = CheckBigWelcomeCanSpSummon(CardId.LovelyLabrynthOfTheSilverCastle) && !activatedCardIdList.Contains(CardId.LovelyLabrynthOfTheSilverCastle + 1); + bool haveLovely = Bot.GetMonsters().Any(card => card.IsFaceup() && card.IsCode(CardId.LovelyLabrynthOfTheSilverCastle)); + if (!noSelect) + { + activatedCardIdList.Add(Card.Id); + } + ResetCooclockEffect(onlyCheck); + return true; + } + } + else { + bool activateFlag = DefaultOnBecomeTarget(); + activateFlag |= Duel.Player == 1 && !activatedCardIdList.Contains(CardId.BigWelcomeLabrynth) && activateTimingFlag; + activateFlag |= Duel.Player == 0 && !summoned && !Bot.HasInHand(CardId.AriannaTheLabrynthServant) && !activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant) + && !(Duel.Phase < DuelPhase.Main1 && Bot.HasInHand(CardId.PotOfExtravagance) && Bot.ExtraDeck.Count() >= 3) + && !(Duel.CurrentChain.Any(card => card.IsCode(CardId.PotOfExtravagance) && card.Controller == 0)); + if (activateFlag && !noSelect) + { + activatedCardIdList.Add(Card.Id); + ResetCooclockEffect(onlyCheck); + return true; + } + } + + return false; + } + + public bool BigWelcomeLabrynthGraveActivate() + { + if (Card.Location == CardLocation.Grave) + { + // bounce enemy + if (Bot.GetMonsters().Any(card => card.Level >= 8 && card.IsFaceup() && card.HasRace(CardRace.Fiend) && !card.HasType(CardType.Xyz | CardType.Link))) + { + // danger monster + ClientCard problemCard = GetProblematicEnemyMonster(-1, true, true, CardType.Trap); + if (problemCard != null) + { + AI.SelectCard(problemCard); + currentDestroyCardList.Add(problemCard); + activatedCardIdList.Add(Card.Id); + return true; + } + // problem spell + if (!Bot.HasInMonstersZone(CardId.LovelyLabrynthOfTheSilverCastle, true, false, true) || + activatedCardIdList.Contains(CardId.LovelyLabrynthOfTheSilverCastle) && activatedCardIdList.Contains(CardId.LovelyLabrynthOfTheSilverCastle + 1)) + { + List problemEnemySpellList = Enemy.SpellZone.Where(c => c?.Data != null && c.IsFaceup() + && c.IsFloodgate() + && !c.IsShouldNotBeTarget() && (c.HasType(CardType.Trap) || Duel.Player == 0)).ToList(); + + problemEnemySpellList.AddRange(Enemy.SpellZone.Where(c => c?.Data != null && c.IsFaceup() && !problemEnemySpellList.Contains(c) + && c.HasType(CardType.Equip | CardType.Pendulum | CardType.Field | CardType.Continuous) + && !c.IsShouldNotBeTarget() && (c.HasType(CardType.Trap) || Duel.Player == 0)).ToList()); + + if (problemEnemySpellList.Count() > 0) + { + AI.SelectCard(problemEnemySpellList); + currentDestroyCardList.Add(problemEnemySpellList[0]); + activatedCardIdList.Add(Card.Id); + return true; + } + } + // best monster + int botBestPower = Util.GetBestPower(Bot); + if (Duel.Player == 1 && Duel.Phase > DuelPhase.Main1 && Duel.Phase < DuelPhase.Main2) + { + List dangerMonsters = Enemy.GetMonsters().Where(card => card.IsFaceup() && card.Attack >= botBestPower + && !currentDestroyCardList.Contains(card) && !card.IsShouldNotBeTarget() && !card.IsShouldNotBeSpellTrapTarget()) + .OrderByDescending(card => card.Attack).ToList(); + if (dangerMonsters.Count() > 0) + { + AI.SelectCard(dangerMonsters); + currentDestroyCardList.Add(dangerMonsters[0]); + activatedCardIdList.Add(Card.Id); + return true; + } + } + // end phase + if (Duel.Phase > DuelPhase.Main2) + { + List returnList = GetNormalEnemyTargetList(true, true, CardType.Trap); + if (returnList.Count() > 0) + { + AI.SelectCard(returnList); + currentDestroyCardList.Add(returnList[0]); + activatedCardIdList.Add(Card.Id); + return true; + } + } + } + + // escape target + List targetList = Bot.GetMonsters().Where(card => card.IsFaceup() && card.HasRace(CardRace.Fiend)).ToList(); + foreach (ClientCard target in targetList) + { + if (Duel.ChainTargets.Contains(target) && !escapeTargetList.Contains(target) + && !(target.IsCode(CardId.UnchainedSoulOfRage, CardId.UnchainedSoulOfAnguish) && Duel.CurrentChain.Contains(target))) + { + AI.SelectCard(target); + escapeTargetList.Add(target); + activatedCardIdList.Add(Card.Id); + return true; + } + } + + // bounce arianna + if (Duel.Player == 0 && Duel.Phase <= DuelPhase.Main2 && !summoned && !Bot.HasInHand(CardId.AriannaTheLabrynthServant) + && !activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant) && !chainSummoningIdList.Contains(CardId.AriannaTheLabrynthServant)) + { + ClientCard target = targetList.FirstOrDefault(card => card.IsCode(CardId.AriannaTheLabrynthServant)); + if (target != null) + { + AI.SelectCard(target); + escapeTargetList.Add(target); + activatedCardIdList.Add(Card.Id); + return true; + } + } + + // trigger furniture/welcome + List checkFurnitureList = new List(Bot.Hand); + checkFurnitureList.AddRange(Bot.GetMonsters()); + if ((CheckRemainInDeck(CardId.WelcomeLabrynth, CardId.BigWelcomeLabrynth) == 0 + || !checkFurnitureList.Any(card => card.IsCode(CardId.LabrynthChandraglier, CardId.LabrynthStovieTorbie))) + && Duel.LastChainPlayer < 0 && Duel.Player == 0 && !Bot.HasInMonstersZone(CardId.LovelyLabrynthOfTheSilverCastle, true, false, true) + && !(cooclockAffected && Bot.HasInHandOrInSpellZone(CardId.BigWelcomeLabrynth))) + { + int checkCount = 0; + List checkIdList = new List { CardId.LabrynthChandraglier, CardId.LabrynthStovieTorbie, CardId.WelcomeLabrynth }; + foreach (int checkId in checkIdList) + { + if (Bot.HasInGraveyard(checkId) && !activatedCardIdList.Contains(checkId + 1)) checkCount++; + } + if (checkCount > 0) + { + ClientCard target = targetList.FirstOrDefault(card => card.IsFaceup() && card.HasRace(CardRace.Fiend) && + ((card.Level <= 4 && !card.HasType(CardType.Link | CardType.Xyz | CardType.Synchro)) || card.IsCode(CardId.LadyLabrynthOfTheSilverCastle))); + if (target != null) + { + AI.SelectCard(target); + escapeTargetList.Add(target); + activatedCardIdList.Add(Card.Id); + return true; + } + } + } + } + + return false; + } + + public bool ChaosAngelSpSummonWith2Monster() + { + if (CheckShouldNoMoreSpSummon(false)) return false; + + List level2MonsterList = new List(); + List level4MonsterList = new List(); + List level6MonsterList = new List(); + List level8MonsterList = new List(); + foreach (ClientCard monster in Bot.GetMonsters()) + { + if (monster.IsFaceup() && !monster.HasType(CardType.Xyz | CardType.Link) && monster.HasAttribute(CardAttribute.Light | CardAttribute.Dark)) + { + if (monster.Level == 2) level2MonsterList.Add(monster); + if (monster.Level == 4) level4MonsterList.Add(monster); + if (monster.Level == 6) level6MonsterList.Add(monster); + if (monster.Level == 8) level8MonsterList.Add(monster); + } + } + level2MonsterList.Sort(CompareUsableAttack); + level4MonsterList.Sort(CompareUsableAttack); + level6MonsterList.Sort(CompareUsableAttack); + level8MonsterList.Sort(CompareUsableAttack); + bool checkFlag = GetProblematicEnemyCardList(true, selfType: CardType.Monster).Count() > 0 && !CheckWhetherNegated(true, true, CardType.Monster); + if (Util.GetBestPower(Bot, true) <= Util.GetBestPower(Enemy)) + { + checkFlag |= Util.GetBestPower(Enemy) <= 3500; + checkFlag |= !Util.GetBestEnemyMonster().IsShouldNotBeTarget() && !Util.GetBestEnemyMonster().IsShouldNotBeMonsterTarget(); + } + // 4+6 + if (level4MonsterList.Count() > 0 && level6MonsterList.Count() > 0) + { + List materials = new List{level4MonsterList[0], level6MonsterList[0]}; + bool summonFlag = checkFlag; + if (Enemy.GetMonsterCount() == 0 && Duel.Phase < DuelPhase.Main2) + summonFlag |= GetBotCurrentTotalAttack() < Enemy.LifePoints && GetBotCurrentTotalAttack(materials) + 3500 >= Enemy.LifePoints; + if (summonFlag) + { + AI.SelectMaterials(materials); + return true; + } + } + // 2+8 + if (level2MonsterList.Count() > 0 && level8MonsterList.Count() > 0) + { + foreach (ClientCard level2 in level2MonsterList) + { + foreach (ClientCard level8 in level8MonsterList) + { + List materials = new List{level2, level8}; + if (checkFlag && !(level8.IsCode(CardId.LovelyLabrynthOfTheSilverCastle) && !level8.IsDisabled() && Bot.HasInSpellZoneOrInGraveyard(CardId.BigWelcomeLabrynth))) + { + AI.SelectMaterials(materials); + return true; + } + if (Enemy.GetMonsterCount() == 0 && GetMaterialAttack(materials) < 3500 && Duel.Phase < DuelPhase.Main2) + { + if (GetBotCurrentTotalAttack() < Enemy.LifePoints && GetBotCurrentTotalAttack(materials) + 3500 >= Enemy.LifePoints) + { + AI.SelectMaterials(materials); + return true; + } + } + } + } + } + return false; + } + public bool ChaosAngelSpSummonWith3Monster() + { + if (CheckShouldNoMoreSpSummon(false)) return false; + + List level2MonsterList = new List(); + List level4MonsterList = new List(); + foreach (ClientCard monster in Bot.GetMonsters()) + { + if (monster.IsFaceup() && !monster.HasType(CardType.Xyz | CardType.Link) && monster.HasAttribute(CardAttribute.Light | CardAttribute.Dark)) + { + if (monster.Level == 2) level2MonsterList.Add(monster); + if (monster.Level == 4) level4MonsterList.Add(monster); + } + } + level2MonsterList.Sort(CompareUsableAttack); + level4MonsterList.Sort(CompareUsableAttack); + bool checkFlag = GetProblematicEnemyCardList(true, selfType: CardType.Monster).Count() > 0 && !CheckWhetherNegated(true, true, CardType.Monster); + if (Util.GetBestPower(Bot, true) <= Util.GetBestPower(Enemy)) + { + checkFlag |= Util.GetBestPower(Enemy) <= 3500; + checkFlag |= !Util.GetBestEnemyMonster().IsShouldNotBeTarget() && !Util.GetBestEnemyMonster().IsShouldNotBeMonsterTarget(); + } + // 2+4+4 + if (level2MonsterList.Count() >= 1 && level4MonsterList.Count() >= 2) + { + foreach (ClientCard level2 in level2MonsterList) + { + for (int level4Index1 = 0; level4Index1 < level4MonsterList.Count() - 1; ++level4Index1) + { + ClientCard level41 = level4MonsterList[level4Index1]; + for (int level4Index2 = level4Index1 + 1; level4Index2 < level4MonsterList.Count(); ++level4Index2) + { + ClientCard level42 = level4MonsterList[level4Index2]; + List materials = new List { level2, level41, level42 }; + bool summonFlag = checkFlag; + if (Enemy.GetMonsterCount() == 0 && Duel.Phase < DuelPhase.Main2) + summonFlag |= GetBotCurrentTotalAttack() < Enemy.LifePoints && GetBotCurrentTotalAttack(materials) + 3500 >= Enemy.LifePoints; + if (summonFlag) + { + AI.SelectMaterials(materials); + return true; + } + } + } + } + } + return false; + } + public bool ChaosAngelActivate() + { + List targetList = GetNormalEnemyTargetList(true, true, CardType.Monster); + if (targetList.Count() > 0) + { + AI.SelectCard(targetList); + currentDestroyCardList.Add(targetList[0]); + return true; + } + + return false; + } + + public bool SummonForTYPHONCheck() + { + if (!Bot.HasInExtra(CardId.SuperStarslayerTYPHON) || Bot.GetMonsters().Any(card => card.IsFaceup())) return false; + if (enemySpSummonFromExLastTurn < 2 && enemySpSummonFromExThisTurn < 2) return false; + if (Card.Level > 4) return false; + + int currentAttack = 0; + YGOSharp.OCGWrapper.NamedCard cardData = YGOSharp.OCGWrapper.NamedCard.Get(Card.Id); + if (cardData != null) currentAttack = cardData.Attack; + List summonList = Bot.Hand.Where(card => card.IsMonster() && card.Level <= 4).ToList(); + foreach (ClientCard checkCard in summonList) + { + cardData = YGOSharp.OCGWrapper.NamedCard.Get(checkCard.Id); + if (cardData != null && cardData.Attack < currentAttack) return false; + } + + return true; + } + public bool SuperStarslayerTYPHONSpSummon() + { + ClientCard material = Bot.GetMonsters().Where(card => card.IsFaceup()).OrderByDescending(card => card.Attack).FirstOrDefault(); + if (material == null || (material.Attack >= 2900 && material.Owner == 0)) return false; + + bool checkFlag = GetProblematicEnemyMonster(material.Attack) != null; + checkFlag |= material.Level <= 4; + checkFlag &= !(material.HasType(CardType.Link) && Duel.Phase >= DuelPhase.Main2); + if (checkFlag) + { + Logger.DebugWriteLine("*** TYPHON select: " + material.Name ?? "UnkonwCard"); + AI.SelectMaterials(material); + return true; + } + + return false; + } + public bool SuperStarslayerTYPHONActivate() + { + if (CheckWhetherNegated()) return false; + List targetList = new List(); + targetList.AddRange(Enemy.GetMonsters().Where(c => !currentDestroyCardList.Contains(c) && + c.IsFloodgate() && c.IsFaceup()).OrderByDescending(card => card.Attack)); + targetList.AddRange(Enemy.GetMonsters().Where(c => !currentDestroyCardList.Contains(c) && + c.IsMonsterDangerous() && c.IsFaceup()).OrderByDescending(card => card.Attack)); + targetList.AddRange(Enemy.GetMonsters().Where(c => !currentDestroyCardList.Contains(c) && + c.IsMonsterInvincible() && c.IsFaceup()).OrderByDescending(card => card.Attack)); + targetList.AddRange(Enemy.GetMonsters().Where(c => !currentDestroyCardList.Contains(c) && + c.GetDefensePower() >= Util.GetBestAttack(Bot) && c.IsAttack()).OrderByDescending(card => card.Attack)); + if (Duel.Phase >= DuelPhase.Main2) + targetList.AddRange(Enemy.GetMonsters().Where(c => !currentDestroyCardList.Contains(c) && + c.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link | CardType.SpSummon)).OrderByDescending(card => card.Attack)); + + if (targetList.Count() > 0) + { + targetList.AddRange(Enemy.GetMonsters().Where(card => card.IsFaceup() && !targetList.Contains(card)).OrderByDescending(card => card.Attack)); + targetList.AddRange(ShuffleList(Enemy.GetMonsters().Where(card => card.IsFacedown() && !targetList.Contains(card)).ToList())); + targetList.AddRange(ShuffleList(Bot.GetMonsters().Where(card => card.IsFacedown() && !targetList.Contains(card)).ToList())); + targetList.AddRange(Bot.GetMonsters().Where(card => card.IsFaceup() && !targetList.Contains(card)).OrderBy(card => card.Attack)); + AI.SelectCard(Card.Overlays); + Logger.DebugWriteLine("TYPHON first target: " + targetList[0]?.Name ?? "UNKNOWN"); + AI.SelectNextCard(targetList); + return true; + } + + return false; + } + + public bool UnchainedAbominationSpSummon() + { + if (CheckShouldNoMoreSpSummon(false)) return false; + if (Enemy.GetMonsterCount() > 0 && Bot.HasInMonstersZone(CardId.UnchainedSoulOfAnguish) && !activatedCardIdList.Contains(CardId.UnchainedSoulOfAnguish)) return false; + List> usableMaterialMultiList = new List>(); + // anguish + 1 + ClientCard anguish = Bot.GetMonsters().FirstOrDefault(card => card.IsCode(CardId.UnchainedSoulOfAnguish)); + if (anguish != null) + { + List materials = GetCanBeUsedForLinkMaterial(true, card => card == anguish); + if (materials.Count() > 0) + { + usableMaterialMultiList.Add(new List { anguish, materials[0] }); + } + } + // link2 + 1 + 1 or link2 + link2 + List link2List = Bot.GetMonsters().Where(card => card.HasType(CardType.Link) && card.LinkCount == 2 + && !(card.IsCode(CardId.MuckrakerFromTheUnderworld) && summonThisTurn.Contains(card))).OrderBy(card => card.Attack).ToList(); + if (link2List.Count() > 0) + { + ClientCard link2Material = null; + ClientCard littleKnight = link2List.FirstOrDefault(card => card.Sequence >= 5 && card.IsCode(CardId.SPLittleKnight)); + if (littleKnight != null) link2Material = littleKnight; + else link2Material = link2List[0]; + if (link2List.Count() >= 2) + { + usableMaterialMultiList.Add(new List { link2Material, link2List.FirstOrDefault(card => card != link2Material) }); + } + List remainList = GetCanBeUsedForLinkMaterial(false, card => card != link2Material && !(card.HasType(CardType.Link) && card.LinkMarker > 2)); + if (remainList.Count() >= 2) + { + usableMaterialMultiList.Add(new List { link2Material, remainList[0], remainList[1] }); + } + } + + // check material list + foreach (List currMaterials in usableMaterialMultiList) + { + bool summonFlag = CheckCanDirectAttack() && GetBotCurrentTotalAttack() < Enemy.LifePoints && GetBotCurrentTotalAttack(currMaterials) + 3000 >= Enemy.LifePoints; + summonFlag |= GetProblematicEnemyMonster(0) != null && GetProblematicEnemyMonster(3000) == null; + + if (summonFlag) + { + AI.SelectMaterials(currMaterials); + return true; + } + } + + return false; + } + public bool UnchainedAbominationActivate() + { + if (CheckWhetherNegated()) return false; + List targetList = GetNormalEnemyTargetList(true, true, CardType.Monster); + if (targetList.Count() == 0) return false; + int logDesc = ActivateDescription; + if (logDesc >= Util.GetStringId(CardId.UnchainedAbomination, 0)) + { + logDesc = Util.GetStringId(CardId.UnchainedAbomination, 0) - 10; + } + Logger.DebugWriteLine("[UnchainedAbomination]desc: " + logDesc + ", timing = " + CurrentTiming); + if (ActivateDescription == Util.GetStringId(CardId.UnchainedAbomination, 0)) activatedCardIdList.Add(Card.Id); + if (ActivateDescription == Util.GetStringId(CardId.UnchainedAbomination, 1) || ActivateDescription == -1) activatedCardIdList.Add(Card.Id + 1); + if (ActivateDescription == Util.GetStringId(CardId.UnchainedAbomination, 2)) activatedCardIdList.Add(Card.Id + 2); + AI.SelectCard(targetList); + + return true; + } + + public bool UnchainedSoulOfAnguishSpSummon() + { + if (CheckShouldNoMoreSpSummon(false)) return false; + + ClientCard unchainedNonLink = Bot.GetMonsters().FirstOrDefault(card => card.IsFaceup() && card.HasSetcode(SetcodeUnchained) && !card.HasType(CardType.Link)); + ClientCard unchainedLink2 = Bot.GetMonsters().FirstOrDefault(card => card.IsFaceup() && card.HasSetcode(SetcodeUnchained) && card.HasType(CardType.Link) && card.LinkCount == 2); + Logger.DebugWriteLine("[Anguish summon] unchainedNonLink = " + unchainedNonLink?.Name + ", unchainedLink2 = " + unchainedLink2?.Name); + if (unchainedNonLink == null && unchainedLink2 == null) return false; + int needMonsterCount = 2; + if (unchainedLink2 != null) needMonsterCount = 1; + if (needMonsterCount == 2 && Bot.HasInExtra(CardId.UnchainedSoulLordOfYama)) return false; + bool needAnguish = !Bot.HasInMonstersZone(CardId.UnchainedSoulOfAnguish) && !activatedCardIdList.Contains(CardId.UnchainedSoulOfAnguish) + && Enemy.GetMonsters().Any(card => card.IsFaceup()); + if (needAnguish) + { + needAnguish = Bot.HasInExtra(CardId.UnchainedSoulOfRage); + needAnguish |= Bot.HasInExtra(CardId.UnchainedAbomination); + needAnguish |= Bot.HasInExtra(CardId.SPLittleKnight) && banSpSummonExceptFiendCount == 0; + } + Logger.DebugWriteLine("[Anguish summon] needAnguish = " + needAnguish.ToString()); + + // check material + if (needMonsterCount == 1) + { + List materialList = GetCanBeUsedForLinkMaterial(needAnguish, card => card == unchainedLink2); + Logger.DebugWriteLine("[Anguish summon 1] material count = " + materialList.Count().ToString()); + if (materialList.Count() == 0) return false; + List selectMaterials = new List{ unchainedLink2, materialList[0]}; + bool summonFlag = needAnguish; + summonFlag |= CheckCanDirectAttack() && GetBotCurrentTotalAttack() < Enemy.LifePoints && GetBotCurrentTotalAttack(selectMaterials) + 2400 >= Enemy.LifePoints; + Logger.DebugWriteLine("[Anguish summon 1] summon flag " + summonFlag.ToString()); + if (summonFlag) + { + AI.SelectMaterials(selectMaterials); + return true; + } + } + if (needMonsterCount == 2) + { + List materialList = GetCanBeUsedForLinkMaterial(needAnguish, card => card == unchainedNonLink); + Logger.DebugWriteLine("[Anguish summon 2] material count = " + materialList.Count().ToString()); + if (materialList.Count() >= 2) + { + List selectMaterials = new List { unchainedNonLink, materialList[0], materialList[1] }; + if (needAnguish || GetMaterialAttack(selectMaterials) < 2400) + { + AI.SelectMaterials(selectMaterials); + return true; + } + } + } + + return false; + } + public bool UnchainedSoulOfAnguishActivate() + { + if (Card.Location == CardLocation.MonsterZone) + { + if (CheckWhetherNegated()) return false; + List targetList = Enemy.GetMonsters().Where(card => card.IsFaceup() && !card.IsShouldNotBeTarget() && !card.IsShouldNotBeMonsterTarget()).OrderByDescending(card => card.Attack).ToList(); + if (targetList.Count() > 0) + { + currentDestroyCardList.Add(targetList[0]); + int summonId = 0; + if (Bot.HasInExtra(CardId.UnchainedAbomination) && GetProblematicEnemyMonster(3000, ignoreCurrentDestroy:true) == null) + summonId = CardId.UnchainedAbomination; + else if (banSpSummonExceptFiendCount == 0 && Bot.HasInExtra(CardId.SPLittleKnight) && GetProblematicEnemyCardList(true, false, CardType.Monster).Count() > 0) + summonId = CardId.SPLittleKnight; + else if (Bot.HasInExtra(CardId.UnchainedSoulOfRage)) summonId = CardId.UnchainedSoulOfRage; + if (summonId > 0) + { + List materialList = new List(targetList){Card}; + Logger.DebugWriteLine("*** Anguish select: " + summonId.ToString()); + + AI.SelectCard(targetList); + AI.SelectNextCard(summonId); + AI.SelectMaterials(materialList); + activatedCardIdList.Add(Card.Id); + } + return true; + } + } + if (Card.Location == CardLocation.Grave) + { + return UnchainRecycleActivate(); + } + + return false; + } + + public bool UnchainedSoulLordOfYamaSpSummon() + { + if (CheckShouldNoMoreSpSummon(false)) return false; + if (Bot.HasInMonstersZone(CardId.UnchainedSoulLordOfYama) || activatedCardIdList.Contains(CardId.UnchainedSoulLordOfYama)) return false; + + bool need3Monster = Bot.HasInExtra(CardId.UnchainedSoulOfAnguish) && !Bot.HasInMonstersZone(CardId.UnchainedSoulOfAnguish) + && !activatedCardIdList.Contains(CardId.UnchainedSoulOfAnguish) && GetProblematicEnemyMonster(canBeTarget:true, selfType: CardType.Monster) != null; + need3Monster |= CheckAtAdvantage() && Duel.Phase == DuelPhase.Main2 + && Bot.HasInExtra(CardId.UnchainedSoulOfRage) && !Bot.HasInMonstersZone(CardId.UnchainedSoulOfRage); + bool haveUnchainSoul = Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasSetcode(SetcodeUnchained)); + if (need3Monster) + { + need3Monster = Bot.HasInExtra(CardId.UnchainedSoulOfRage); + need3Monster |= Bot.HasInExtra(CardId.UnchainedAbomination); + need3Monster |= Bot.HasInExtra(CardId.SPLittleKnight) && banSpSummonExceptFiendCount == 0; + } + // check material + List materialList = GetCanBeUsedForLinkMaterial(need3Monster, + card => !card.HasRace(CardRace.Fiend) || (card.HasType(CardType.Link) && card.HasSetcode(SetcodeUnchained))); + Logger.DebugWriteLine("[Yama Summon]need3Monster = " + need3Monster.ToString() + ", material count = " + materialList.Count()); + for (int index1 = 0; index1 < materialList.Count() - 1; ++ index1) + { + ClientCard material1 = materialList[index1]; + for (int index2 = index1 + 1; index2 < materialList.Count(); ++ index2) + { + ClientCard material2 = materialList[index2]; + List selectMaterials = new List{material1, material2}; + if (need3Monster && materialList.Count() == 2 && (activatedCardIdList.Contains(CardId.UnchainedSoulOfSharvara) || Bot.GetSpells().Count() == 0)) + { + // only for attack + if (GetProblematicEnemyMonster() != null || !CheckCanDirectAttack() || GetMaterialAttack(selectMaterials) >= 2000) return false; + } + bool summonFlag = need3Monster; + summonFlag |= Enemy.GetMonsterCount() == 0 && GetMaterialAttack(selectMaterials) < 2000; + summonFlag |= CheckAtAdvantage() && !haveUnchainSoul; + if (summonFlag) + { + AI.SelectMaterials(selectMaterials); + return true; + } + } + } + + return false; + } + public bool UnchainedSoulLordOfYamaActivate() + { + if (Card.Location == CardLocation.MonsterZone && (ActivateDescription == Util.GetStringId(CardId.UnchainedSoulLordOfYama, 0) || ActivateDescription == -1)) + { + // search + if (CheckWhetherNegated()) return false; + AI.SelectCard(CardId.UnchainedSoulOfSharvara, CardId.UnchainedAbomination, CardId.UnchainedSoulOfAnguish, CardId.UnchainedSoulOfRage); + activatedCardIdList.Add(Card.Id); + return true; + } + else if (Card.Location == CardLocation.Grave) + { + // spsummon & destroy + ClientCard chaosAngel = null; + ClientCard abomination = null; + ClientCard lady = null; + ClientCard lovely = null; + ClientCard arianna = null; + ClientCard bestAttack = null; + ClientCard rage = null; + foreach (ClientCard grave in Bot.Graveyard) + { + if (grave.IsCode(CardId.ChaosAngel) && grave.ProcCompleted != 0 && !dimensionalBarrierAnnouced.Contains(HintMsg.SYNCHRO)) chaosAngel = grave; + if (grave.IsCode(CardId.UnchainedSoulOfRage) && grave.ProcCompleted != 0) rage = grave; + if (grave.IsCode(CardId.UnchainedAbomination) && grave.ProcCompleted != 0) abomination = grave; + if (grave.IsCode(CardId.LadyLabrynthOfTheSilverCastle)) lady = grave; + if (grave.IsCode(CardId.LovelyLabrynthOfTheSilverCastle)) lovely = grave; + if (grave.IsCode(CardId.AriannaTheLabrynthServant)) arianna = grave; + if (Card != grave && grave.IsMonster() && grave.HasRace(CardRace.Fiend)) + { + if (!grave.IsCanRevive()) continue; + if (bestAttack == null || grave.Attack > bestAttack.Attack) bestAttack = grave; + } + } + + ClientCard select = null; + bool destroyWelcome = false; + if (chaosAngel != null && (GetProblematicEnemyCardList(selfType: CardType.Monster).Count() > 0 || + (Bot.GetMonsterCount() == 0 && Duel.Phase > DuelPhase.Main1 && Duel.Phase < DuelPhase.Main2))) + { + select = chaosAngel; + } + if (select == null && abomination != null && (GetProblematicEnemyCardList(selfType: CardType.Monster).Count() > 0 || + (Bot.GetMonsterCount() == 0 && Duel.Phase > DuelPhase.Main1 && Duel.Phase < DuelPhase.Main2))) + { + select = abomination; + Logger.DebugWriteLine("[Yama] timing: " + CurrentTiming.ToString()); + if (Bot.HasInSpellZone(CardId.WelcomeLabrynth) && !(Duel.Phase > DuelPhase.Main1 && Duel.Phase < DuelPhase.Main2) + && !activatedCardIdList.Contains(CardId.UnchainedAbomination)) + { + destroyWelcome = true; + } + } + if (select == null && rage != null && (Duel.Player == 0 || (!activatedCardIdList.Contains(CardId.UnchainedSoulOfRage) && (Duel.Phase == DuelPhase.Main1 || Duel.Phase == DuelPhase.Main2))) + && Bot.HasInExtra(new List { CardId.UnchainedSoulOfAnguish, CardId.SPLittleKnight })) select = rage; + if (select == null && arianna != null && Duel.Player == 0 && !activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant)) select = arianna; + if (select == null && lovely != null && Duel.Player == 1 && Util.GetBestAttack(Enemy) < 2900) select = lovely; + if (select == null && lady != null && Duel.Player == 1 && Util.GetBestAttack(Enemy) < 3000) select = lady; + if (select == null && arianna != null && !activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant)) select = arianna; + if (select == null && bestAttack != null) select = bestAttack; + + if (select != null) + { + activatedCardIdList.Add(Card.Id + 1); + AI.SelectCard(select); + if (destroyWelcome) + { + AI.SelectYesNo(true); + AI.SelectNextCard(CardId.WelcomeLabrynth); + } else { + AI.SelectYesNo(false); + } + return true; + } + } + + return false; + } + + public bool UnchainedSoulOfRageSpSummon() + { + if (CheckShouldNoMoreSpSummon(false) || CheckWhetherNegated(true, true, CardType.Monster | CardType.Link)) return false; + if (Bot.HasInMonstersZone(CardId.UnchainedSoulOfRage)) return false; + + ClientCard unchained = Bot.GetMonsters().FirstOrDefault(card => card.IsFaceup() && card.HasSetcode(SetcodeUnchained) + && !card.IsCode(CardId.UnchainedSoulOfAnguish, CardId.UnchainedAbomination)); + if (unchained == null) return false; + + bool summonFlag = CheckAtAdvantage() && Util.IsTurn1OrMain2(); + summonFlag |= !(Bot.HasInExtra(CardId.UnchainedSoulOfAnguish) && !activatedCardIdList.Contains(CardId.UnchainedSoulOfAnguish)) && Util.IsTurn1OrMain2(); + if (summonFlag) + { + summonFlag = Bot.HasInExtra(CardId.UnchainedSoulOfAnguish); + summonFlag |= Bot.HasInExtra(CardId.SPLittleKnight) && banSpSummonExceptFiendCount == 0; + } + + List materialList = GetCanBeUsedForLinkMaterial(Util.IsTurn1OrMain2(), + card => !card.HasRace(CardRace.Fiend) || card == unchained); + if (materialList.Count() > 0) + { + List selectMaterials = new List{unchained, materialList[0]}; + summonFlag |= Enemy.GetMonsterCount() == 0 && GetBotCurrentTotalAttack() < Enemy.LifePoints && GetBotCurrentTotalAttack(selectMaterials) + 1800 >= Enemy.LifePoints; + if (summonFlag) + { + AI.SelectMaterials(selectMaterials); + return true; + } + } + + return false; + } + public bool UnchainedSoulOfRageActivate() + { + if (Card.Location == CardLocation.MonsterZone) + { + if (CheckWhetherNegated()) return false; + bool activateFlag = DefaultOnBecomeTarget() && !Util.ChainContainsCard(CardId.EscapeOfTheUnchained); + ClientCard problemMonster = GetProblematicEnemyMonster(-1, true, true, CardType.Monster); + List targetList = Enemy.GetMonsters().Where(card => card.IsFaceup() && !card.IsShouldNotBeTarget() && !card.IsShouldNotBeTarget()).OrderBy(card => card.Attack).ToList(); + if (problemMonster != null) targetList.Insert(0, problemMonster); + + activateFlag |= (CurrentTiming & hintTimingMainEnd) > 0 && Util.IsOneEnemyBetterThanValue(Card.Attack, true); + activateFlag |= problemMonster != null; + + if (activateFlag && targetList.Count() > 0) + { + ClientCard target = targetList[0]; + int summonId = 0; + if (Bot.HasInExtra(CardId.UnchainedAbomination) && GetProblematicEnemyMonster(3000) == null + && target.HasType(CardType.Link) && target.LinkCount == 2) summonId = CardId.UnchainedSoulOfAnguish; + else if (banSpSummonExceptFiendCount == 0 && Bot.HasInExtra(CardId.SPLittleKnight)) summonId = CardId.SPLittleKnight; + else if (Bot.HasInExtra(CardId.UnchainedSoulOfAnguish) && GetProblematicEnemyMonster(2400) == null) summonId = CardId.UnchainedSoulOfAnguish; + List materialList = new List(targetList){Card}; + + AI.SelectCard(targetList); + AI.SelectNextCard(summonId); + AI.SelectMaterials(materialList); + activatedCardIdList.Add(Card.Id); + escapeTargetList.Add(Card); + currentDestroyCardList.Add(target); + return true; + } + } + if (Card.Location == CardLocation.Grave) + { + return UnchainRecycleActivate(); + } + + return false; + } + + public bool UnchainRecycleActivate() + { + AI.SelectCard(CardId.UnchainedSoulOfSharvara, CardId.LovelyLabrynthOfTheSilverCastle, CardId.AriannaTheLabrynthServant, + CardId.UnchainedAbomination, CardId.LabrynthStovieTorbie, CardId.LabrynthChandraglier, CardId.LabrynthCooclock, + CardId.AriasTheLabrynthButler, CardId.ArianeTheLabrynthServant); + activatedCardIdList.Add(Card.Id + 1); + + return true; + } + + public bool SPLittleKnightSpSummon() + { + if (CheckCanDirectAttack()) + { + // for attack + List materialList = SPLittleKnightSelectMaterial(); + if (materialList.Count() >= 2 && GetMaterialAttack(materialList) < 1600) + { + AI.SelectMaterials(materialList); + return true; + } + } else if (!CheckWhetherNegated(true, true, CardType.Monster | CardType.Link) && GetProblematicEnemyCardList(true, selfType: CardType.Monster).Count() > 0) + { + // for remove + List materialList = SPLittleKnightSelectMaterial(true); + if (materialList.Count() >= 2 && materialList.Any(card => card.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link))) + { + AI.SelectMaterials(materialList); + return true; + } + } + return false; + } + public List SPLittleKnightSelectMaterial(bool needToUseEffect = false) + { + List usedMaterialList = new List(); + if (Bot.GetMonstersExtraZoneCount() > 0) + { + ClientCard botMonsterExtraZome = Bot.GetMonstersInExtraZone()[0]; + if (botMonsterExtraZome.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Pendulum) || botMonsterExtraZome.IsCode(CardId.RelinquishedAnima)) + { + usedMaterialList.Add(botMonsterExtraZome); + if (botMonsterExtraZome.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link)) needToUseEffect = false; + } + List materialList = GetCanBeUsedForLinkMaterial(true, card => card == botMonsterExtraZome); + if (materialList.Count() > 0) + { + foreach (ClientCard card in materialList) + { + if (!needToUseEffect || card.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz) || (card.HasType(CardType.Link) && card.LinkCount <= 2)) + { + usedMaterialList.Add(card); + if (card.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link)) needToUseEffect = false; + } + if (usedMaterialList.Count() >= 2) break; + } + } + if (usedMaterialList.Count() < 2) usedMaterialList.Clear(); + } else { + List materialList = GetCanBeUsedForLinkMaterial(true, card => !needToUseEffect + || card.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz) || (card.HasType(CardType.Link) && card.LinkCount <= 2)); + if (materialList.Count() >= 2) + { + for (int idx1 = 0; idx1 < materialList.Count() - 1; ++ idx1) + { + ClientCard material1 = materialList[idx1]; + if (material1.HasType(CardType.Link) && material1.LinkCount >= 3) continue; + bool flag1 = !needToUseEffect || material1.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link); + for (int idx2 = 0; idx2 < materialList.Count(); ++ idx2) + { + ClientCard material2 = materialList[idx2]; + if (material2.HasType(CardType.Link) && material2.LinkCount >= 3) continue; + bool flag2 = !needToUseEffect || material2.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link); + if (flag1 || flag2) + { + return new List{material1, material2}; + } + } + } + } + } + + return usedMaterialList; + } + + public bool SPLittleKnightActivate() + { + if (ActivateDescription == -1 || ActivateDescription == Util.GetStringId(CardId.SPLittleKnight, 0)) + { + // banish card + List problemCardList = GetProblematicEnemyCardList(true, selfType: CardType.Monster); + problemCardList.AddRange(GetDangerousCardinEnemyGrave(false)); + problemCardList.AddRange(GetNormalEnemyTargetList(true, true, CardType.Monster)); + problemCardList.AddRange(Enemy.Graveyard.Where(card => card.HasType(CardType.Monster)).OrderByDescending(card => card.Attack)); + problemCardList.AddRange(Enemy.Graveyard.Where(card => !card.HasType(CardType.Monster))); + if (problemCardList.Count() > 0) + { + AI.SelectCard(problemCardList); + activatedCardIdList.Add(Card.Id); + return true; + } + } else if (ActivateDescription == Util.GetStringId(CardId.SPLittleKnight, 1)) + { + ClientCard selfMonster = null; + foreach (ClientCard target in Bot.GetMonsters()) + { + if (Duel.ChainTargets.Contains(target) && !escapeTargetList.Contains(target)) + { + selfMonster = target; + break; + } + } + if (selfMonster == null) + { + if (Duel.Player == 1) + { + selfMonster = Bot.GetMonsters().Where(card => card.IsAttack()).OrderBy(card => card.Attack).FirstOrDefault(); + if (!Util.IsOneEnemyBetterThanValue(selfMonster.Attack, true)) selfMonster = null; + } + } + if (selfMonster != null) + { + ClientCard nextMonster = null; + List selfTargetList = Bot.GetMonsters().Where(card => card != selfMonster).ToList(); + if (Enemy.GetMonsterCount() == 0 && selfTargetList.Count() > 0) + { + selfTargetList.Sort(CompareUsableAttack); + nextMonster = selfTargetList[0]; + escapeTargetList.Add(nextMonster); + } + if (Enemy.GetMonsterCount() > 0) + { + nextMonster = GetBestEnemyMonster(false, true, true); + currentDestroyCardList.Add(nextMonster); + } + if (nextMonster != null) + { + AI.SelectCard(selfMonster); + AI.SelectNextCard(nextMonster); + escapeTargetList.Add(selfMonster); + activatedCardIdList.Add(Card.Id + 1); + return true; + } + } + } + + return false; + } + + public bool MuckrakerFromTheUnderworldSpSummon() + { + List materialList = GetCanBeUsedForLinkMaterial(true, card => card.HasType(CardType.Link)); + if (materialList.Count() < 2) return false; + bool willBeNegated = CheckWhetherNegated(true, true, CardType.Monster | CardType.Link) && Bot.Hand.Count() > 0; + bool canRebornAngel = Bot.Graveyard.Any(card => card.IsCanRevive() && card.IsCode(CardId.ChaosAngel)) && !willBeNegated; + bool canRebornLovely = Bot.Graveyard.Any(card => card.IsCode(CardId.LovelyLabrynthOfTheSilverCastle)) && !willBeNegated; + int bestAttackGrave = 0; + bool chaosAngelFlag = GetProblematicEnemyCardList(true, selfType: CardType.Monster).Count() > 0 && !CheckWhetherNegated(true, true, CardType.Monster); + foreach (ClientCard grave in Bot.Graveyard) + { + if (grave.IsMonster() && grave.HasRace(CardRace.Fiend)) + { + if (!grave.IsCanRevive()) continue; + if (grave.Attack > bestAttackGrave) bestAttackGrave = grave.Attack; + } + } + for (int idx1 = 0; idx1 < materialList.Count() - 1; ++ idx1) + { + ClientCard material1 = materialList[idx1]; + for (int idx2 = idx1 + 1; idx2 < materialList.Count(); ++ idx2) + { + ClientCard material2 = materialList[idx1]; + List currentList = new List { material1, material2 }; + bool summonFlag = chaosAngelFlag && (canRebornAngel || (currentList.Any(card => card.IsCode(CardId.ChaosAngel)) && !willBeNegated)); + summonFlag |= Enemy.GetMonsterCount() == 0 && canRebornLovely; + summonFlag |= !activatedCardIdList.Contains(CardId.LovelyLabrynthOfTheSilverCastle) && Bot.Graveyard.Any(card => card.Type == (int)CardType.Trap) + && currentList.Any(card => card.IsDisabled() && card.IsCode(CardId.LovelyLabrynthOfTheSilverCastle)); + if (CheckCanDirectAttack()) + { + summonFlag |= GetBotCurrentTotalAttack() < Enemy.LifePoints && GetBotCurrentTotalAttack(currentList) + bestAttackGrave >= Enemy.LifePoints; + summonFlag |= GetMaterialAttack(currentList) < 1000; + } + if (summonFlag) + { + AI.SelectMaterials(currentList); + return true; + } + } + } + return false; + } + public bool MuckrakerFromTheUnderworldActivate() + { + if (ActivateDescription == Util.GetStringId(CardId.MuckrakerFromTheUnderworld, 0)) + { + if (CheckWhetherNegated()) return false; + ClientCard chaosAngel = null; + ClientCard lovely = null; + ClientCard arianna = null; + ClientCard bestAttack = null; + foreach (ClientCard grave in Bot.Graveyard) + { + if (grave.IsCode(CardId.ChaosAngel) && grave.ProcCompleted != 0 && !dimensionalBarrierAnnouced.Contains(HintMsg.SYNCHRO)) chaosAngel = grave; + if (grave.IsCode(CardId.LovelyLabrynthOfTheSilverCastle)) lovely = grave; + if (grave.IsCode(CardId.AriannaTheLabrynthServant)) arianna = grave; + if (Card != grave && grave.IsMonster() && grave.HasRace(CardRace.Fiend)) + { + if (!grave.IsCanRevive()) continue; + if (bestAttack == null || grave.Attack > bestAttack.Attack) bestAttack = grave; + } + } + + ClientCard rebornTarget = null; + if (chaosAngel != null && (GetProblematicEnemyCardList(true, selfType: CardType.Monster).Count() > 0)) rebornTarget = chaosAngel; + if (rebornTarget == null && lovely != null && Util.GetBestAttack(Enemy) < 2900 && + (!activatedCardIdList.Contains(CardId.LovelyLabrynthOfTheSilverCastle) || Bot.HasInSpellZoneOrInGraveyard(CardId.BigWelcomeLabrynth))) rebornTarget = lovely; + if (rebornTarget == null && bestAttack != null && CheckCanDirectAttack() + && GetBotCurrentTotalAttack() < Enemy.LifePoints && GetBotCurrentTotalAttack() + bestAttack.Attack >= Enemy.LifePoints) rebornTarget = bestAttack; + if (rebornTarget == null && arianna != null && Duel.Player == 0 && !activatedCardIdList.Contains(CardId.AriannaTheLabrynthServant)) rebornTarget = arianna; + if (rebornTarget == null && bestAttack != null) rebornTarget = bestAttack; + if (rebornTarget != null) + { + AI.SelectCard(rebornTarget); + AI.SelectNextCard(FurnitureGetCost()); + activatedCardIdList.Contains(Card.Id); + banSpSummonExceptFiendCount = Math.Max(1, banSpSummonExceptFiendCount); + return true; + } + } + + return false; + } + + public bool RelinquishedAnimaSpSummon() + { + if (CheckWhetherNegated()) return false; + // summon to use effect + ClientCard enemyLeftEx = Enemy.MonsterZone[6]; + if (enemyLeftEx != null && enemyLeftEx.HasLinkMarker((int)CardLinkMarker.Top) && !enemyLeftEx.IsShouldNotBeTarget() && !enemyLeftEx.IsShouldNotBeMonsterTarget()) + { + ClientCard selfMonsterZone1 = Bot.MonsterZone[1]; + if (selfMonsterZone1 == null) + { + AI.SelectMaterials(CardId.LabrynthCooclock); + AI.SelectPlace(Zones.z1); + return true; + } + else if (!selfMonsterZone1.HasType(CardType.Xyz | CardType.Link | CardType.Token) && selfMonsterZone1.Level == 1) + { + AI.SelectMaterials(selfMonsterZone1); + AI.SelectPlace(Zones.z1); + return true; + } + } + ClientCard enemyRightEx = Enemy.MonsterZone[5]; + if (enemyRightEx != null && enemyRightEx.HasLinkMarker((int)CardLinkMarker.Top) && !enemyRightEx.IsShouldNotBeTarget() && !enemyRightEx.IsShouldNotBeMonsterTarget()) + { + ClientCard selfMonsterZone3 = Bot.MonsterZone[3]; + if (selfMonsterZone3 == null) + { + AI.SelectMaterials(CardId.LabrynthCooclock); + AI.SelectPlace(Zones.z3); + return true; + } + else if (!selfMonsterZone3.HasType(CardType.Xyz | CardType.Link | CardType.Token) && selfMonsterZone3.Level == 1) + { + AI.SelectMaterials(selfMonsterZone3); + AI.SelectPlace(Zones.z3); + return true; + } + } + + if (Bot.MonsterZone[5] != null || Bot.MonsterZone[6] != null) return false; + ClientCard enemyMonsterLeft = Enemy.MonsterZone[3]; + ClientCard enemyMonsterRight = Enemy.MonsterZone[1]; + if (Enemy.MonsterZone[6] != null) enemyMonsterLeft = null; + if (enemyMonsterLeft != null && enemyMonsterLeft.IsFacedown()) enemyMonsterLeft = null; + if (enemyMonsterLeft != null && (enemyMonsterLeft.IsShouldNotBeMonsterTarget() || enemyMonsterLeft.IsShouldNotBeTarget())) enemyMonsterLeft = null; + + if (Enemy.MonsterZone[5] != null) enemyMonsterRight = null; + if (enemyMonsterRight != null && (enemyMonsterRight.IsShouldNotBeMonsterTarget() || enemyMonsterRight.IsShouldNotBeTarget())) enemyMonsterRight = null; + if (enemyMonsterRight != null && enemyMonsterRight.IsFacedown()) enemyMonsterRight = null; + + int place = -1; + if (enemyMonsterLeft != null && enemyMonsterRight == null) place = Zones.z5; + if (enemyMonsterLeft == null && enemyMonsterRight != null) place = Zones.z6; + if (enemyMonsterLeft != null && enemyMonsterRight != null) + { + if (enemyMonsterLeft.IsFloodgate() && !enemyMonsterRight.IsFloodgate()) place = Zones.z5; + else if (!enemyMonsterLeft.IsFloodgate() && enemyMonsterRight.IsFloodgate()) place = Zones.z6; + else + { + if (enemyMonsterLeft.GetDefensePower() >= enemyMonsterRight.GetDefensePower()) place = Zones.z5; + else place = Zones.z6; + } + } + if (place >= 0) + { + AI.SelectMaterials(Bot.GetMonsters().Where(card => card.IsFaceup() && !card.HasType(CardType.Xyz | CardType.Link | CardType.Token) && card.Level == 1) + .OrderBy(card => card.Attack).ToList()); + AI.SelectPlace(place); + return true; + } + + // summon for little knight + if (Bot.HasInExtra(CardId.SPLittleKnight) && Bot.GetMonsters().Count(card => card.IsFaceup()) >= 2 + && !Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasType(CardType.Fusion | CardType.Synchro | CardType.Xyz | CardType.Link))) + { + if (GetProblematicEnemyCardList(true, selfType: CardType.Monster).Count() > 0) + { + AI.SelectMaterials(Bot.GetMonsters().Where(card => card.IsFaceup() && !card.HasType(CardType.Xyz | CardType.Link | CardType.Token) && card.Level == 1) + .OrderBy(card => card.Attack).ToList()); + return true; + } + } + return false; + } + public bool RelinquishedAnimaActivate() + { + if (CheckWhetherNegated()) return false; + activatedCardIdList.Add(Card.Id); + Dictionary placeList = new Dictionary{ {1, 6}, {3, 5}, {5, 3}, {6, 1} }; + foreach (KeyValuePair placePair in placeList) + { + if (Bot.MonsterZone[placePair.Key] == Card && Enemy.MonsterZone[placePair.Value] != null) + { + currentDestroyCardList.Add(Enemy.MonsterZone[placePair.Value]); + break; + } + } + return true; + } + + public bool MonsterRepos() + { + int selfAttack = Card.Attack + 1; + + if (selfAttack <= 1) + return !Card.IsDefense(); + + int bestAttack = 0; + foreach (ClientCard card in Bot.GetMonsters()) + { + int attack = card.Attack; + if (attack >= bestAttack) + { + bestAttack = attack; + } + } + + bool enemyBetter = Util.IsAllEnemyBetterThanValue(bestAttack, true); + + if (Card.IsAttack() && enemyBetter) + return true; + if (Card.IsDefense() && !enemyBetter) + return true; + return false; + } + + public bool ReposForLabrynth() + { + if (!activatedCardIdList.Contains(CardId.BigWelcomeLabrynth) && Bot.HasInSpellZoneOrInGraveyard(CardId.BigWelcomeLabrynth)) + return Card.IsFacedown(); + return false; + } + + public bool SpellSetCheck() + { + if (Duel.Phase == DuelPhase.Main1 && Bot.HasAttackingMonster() && Duel.Turn > 1) return false; + if (Card.IsCode(CardId.BigWelcomeLabrynth) && Bot.HasInSpellZone(Card.Id)) return false; + if (Card.IsCode(CardId.TransactionRollback) && !Bot.HasInSpellZone(CardId.TransactionRollback)) + { + // check enemy grave trap + bool haveCopyTrap = false; + if (Enemy.Graveyard.Any(card => card.IsCode( + CardId.WelcomeLabrynth, CardId.BigWelcomeLabrynth, _CardId.InfiniteImpermanence, _CardId.DimensionalBarrier, CardId.DestructiveDarumaKarmaCannon, + _CardId.CompulsoryEvacuationDevice, _CardId.BreakthroughSkill + ))) + { + haveCopyTrap = true; + } + + if (!haveCopyTrap && !Bot.HasInHand(CardId.UnchainedSoulOfSharvara)) return false; + } + if (Card.IsCode(CardId.EscapeOfTheUnchained) && !Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasSetcode(SetcodeUnchained))) return false; + + // select place + if (Card.IsTrap() || Card.HasType(CardType.QuickPlay)) + { + List avoidList = new List(); + int setFornfiniteImpermanence = 0; + for (int i = 0; i < 5; ++i) + { + if (Enemy.SpellZone[i] != null && Enemy.SpellZone[i].IsFaceup() && Bot.SpellZone[4 - i] == null) + { + avoidList.Add(4 - i); + setFornfiniteImpermanence += (int)System.Math.Pow(2, 4 - i); + } + } + if (Bot.HasInHand(_CardId.InfiniteImpermanence)) + { + if (Card.IsCode(_CardId.InfiniteImpermanence)) + { + AI.SelectPlace(setFornfiniteImpermanence); + return true; + } else + { + SelectSTPlace(Card, false, avoidList); + 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; + } + + public bool SpellSetForCooClockCheck() + { + // set to destroy for Sharvara + if (Card.IsCode(CardId.PotOfExtravagance, CardId.TransactionRollback, CardId.WelcomeLabrynth) && Bot.HasInHand(CardId.UnchainedSoulOfSharvara) + && !activatedCardIdList.Contains(CardId.UnchainedSoulOfSharvara)) + { + SelectSTPlace(Card, false); + return true; + } + // set to activate by cooclock + bool haveLabrynth = Bot.GetMonsters().Any(card => card.IsFaceup() && card.HasSetcode(SetcodeLabrynth)); + if (!cooclockAffected || (haveLabrynth && Bot.HasInHand(CardId.LabrynthCooclock) && !activatedCardIdList.Contains(CardId.LabrynthCooclock))) return false; + if (!Card.IsCode(CardId.BigWelcomeLabrynth, CardId.WelcomeLabrynth, _CardId.InfiniteImpermanence, _CardId.DimensionalBarrier)) return false; + if (haveLabrynth) + { + SelectSTPlace(Card, true); + return true; + } + if (!Card.IsCode(CardId.BigWelcomeLabrynth, CardId.WelcomeLabrynth)) return false; + if (!summoned && Bot.Hand.Any(card => card.IsMonster() && card.Level <= 4 && card.HasSetcode(SetcodeLabrynth))) + { + SelectSTPlace(Card, true); + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/Game/AI/DefaultExecutor.cs b/Game/AI/DefaultExecutor.cs index 5ff3b3b6..bcd81b5b 100644 --- a/Game/AI/DefaultExecutor.cs +++ b/Game/AI/DefaultExecutor.cs @@ -125,6 +125,7 @@ protected class _CardId public const int VaylantzWorld_ShinraBansho = 49568943; public const int VaylantzWorld_KonigWissen = 75952542; public const int DivineArsenalAAZEUS_SkyThunder = 90448279; + public const int LightningStorm = 14532163; public const int BelialMarquisOfDarkness = 33655493; public const int ChirubiméPrincessOfAutumnLeaves = 87294988; @@ -223,6 +224,8 @@ protected DefaultExecutor(GameAI ai, Duel duel) AddExecutor(ExecutorType.Activate, _CardId.SantaClaws); } + protected int lightningStormOption = -1; + /// /// Defined: /// if monster with code as KEY, other monsters with rules as VALUE won't be targeted for attack. @@ -395,6 +398,9 @@ public override bool OnPreBattleBetween(ClientCard attacker, ClientCard defender } } + if (attacker.EquipCards.Any(equip => equip.IsCode(_CardId.MoonMirrorShield) && !equip.IsDisabled())) + attacker.RealPower = defender.RealPower + 100; + if (!defender.IsDisabled()) { Func, bool> defenderRule = (card, monsterList) => false; @@ -430,6 +436,9 @@ public override bool OnPreBattleBetween(ClientCard attacker, ClientCard defender if (Enemy.HasInSpellZone(_CardId.CrusadiaVanguard, true) && Enemy.GetMonsters().Any(card => card.HasSetcode(_Setcode.Crusadia) && card.HasType(CardType.Link)) && !defender.HasType(CardType.Link)) return false; + + if (defender.IsCode(_CardId.RescueACEHydrant) && !defender.IsDisabled() && Enemy.GetMonsters().Any(monster => monster.HasSetcode(_Setcode.RescueACE) && !monster.IsCode(_CardId.RescueACEHydrant))) + return false; if (Enemy.HasInSpellZone(_CardId.SilenforcingBarrier, true) && Enemy.HasInMonstersZone(_CardId.NovoxTheSilenforcerDisciple, faceUp: true) && !defender.HasType(CardType.Ritual)) return false; @@ -1025,6 +1034,8 @@ protected bool DefaultOnBecomeTarget() if (Util.ChainContainsCard(destroyAllList)) return true; if (Enemy.HasInSpellZone(destroyAllOpponentSpellList, true) && Card.Location == CardLocation.SpellZone) 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) return false; } @@ -1120,12 +1131,11 @@ protected bool DefaultDimensionalBarrier() bool nontuner = false; foreach (ClientCard monster in monsters) { - if (monster.HasType(CardType.Tuner)) - tuner = true; - else if (!monster.HasType(CardType.Xyz) && !monster.HasType(CardType.Link)) + if (!monster.HasType(CardType.Xyz | CardType.Link)) { - nontuner = true; - levels[monster.Level] = levels[monster.Level] + 1; + if (monster.HasType(CardType.Tuner)) tuner = true; + else nontuner = true; + if (!monster.HasType(CardType.Token)) levels[monster.Level] = levels[monster.Level] + 1; } if (monster.IsOneForXyz()) @@ -1156,7 +1166,8 @@ protected bool DefaultDimensionalBarrier() } } ClientCard lastchaincard = Util.GetLastChainCard(); - if (Duel.LastChainPlayer == 1 && lastchaincard != null && !lastchaincard.IsDisabled()) + if (Duel.LastChainPlayer == 1 && lastchaincard != null && !lastchaincard.IsDisabled() + && (lastchaincard.HasType(CardType.Spell | CardType.Trap) || lastchaincard.Location == CardLocation.MonsterZone)) { if (lastchaincard.HasType(CardType.Ritual)) { @@ -1454,5 +1465,21 @@ protected bool DefaultVaylantzWorld_KonigWissen() return false; } + + public override void OnReceivingAnnouce(int player, int data) + { + if (player == 1 && data == Util.GetStringId(_CardId.LightningStorm, 0) || data == Util.GetStringId(_CardId.LightningStorm, 1)) + { + lightningStormOption = data - Util.GetStringId(_CardId.LightningStorm, 0); + } + + base.OnReceivingAnnouce(player, data); + } + + public override void OnChainEnd() + { + lightningStormOption = -1; + base.OnChainEnd(); + } } } diff --git a/Game/AI/Enums/Floodgate.cs b/Game/AI/Enums/Floodgate.cs index bf2bd36a..f3f192b8 100644 --- a/Game/AI/Enums/Floodgate.cs +++ b/Game/AI/Enums/Floodgate.cs @@ -71,6 +71,7 @@ public enum Floodgate ElShaddollConstruct = 20366274, ElShaddollGrysra = 48424886, ElShaddollWinda = 94977269, + HotRedDragonArchfiendAbyss = 9753964, UltimateConductorTytanno = 18940556, OvertexCoatls = 41782653, FirePrison = 269510, diff --git a/Game/AI/Enums/FusionSpell.cs b/Game/AI/Enums/FusionSpell.cs index f157cc3a..199558ab 100644 --- a/Game/AI/Enums/FusionSpell.cs +++ b/Game/AI/Enums/FusionSpell.cs @@ -67,6 +67,7 @@ public enum FusionSpell FaceCardFusion = 29062925, MyutantFusion = 42577802, MyutantCry = 31855260, + FallenOfAlbaz = 68468459, GreaterPolymerization = 7614732, UltimateFusion = 71143015, BrandedFusion = 44362883, diff --git a/Game/AI/Executor.cs b/Game/AI/Executor.cs index b1284a9c..7ef678d6 100644 --- a/Game/AI/Executor.cs +++ b/Game/AI/Executor.cs @@ -104,6 +104,12 @@ public virtual void OnChainEnd() { // For overriding } + + public virtual void OnReceivingAnnouce(int player, int data) + { + // For overriding + } + public virtual void OnNewPhase() { // Some AI need do something on new phase @@ -118,7 +124,7 @@ public virtual void OnDraw(int player) // Some AI need do something on draw } - public virtual void OnMove(int cardId, int previousControler, int previousLocation, int currentControler, int currentLocation) + public virtual void OnMove(ClientCard card, int previousControler, int previousLocation, int currentControler, int currentLocation) { // Some AI need do something on card's moving } diff --git a/Game/AI/HintMsg.cs b/Game/AI/HintMsg.cs index 65634b42..2f868d0c 100644 --- a/Game/AI/HintMsg.cs +++ b/Game/AI/HintMsg.cs @@ -57,6 +57,11 @@ public static class HintMsg ToZone = 571, Counter = 572, Disable = 573, - OperateCard = 574; + OperateCard = 574, + RITUAL = 1057, + FUSION = 1056, + SYNCHRO = 1063, + XYZ = 1073, + PENDULUM = 1074; } } \ No newline at end of file diff --git a/Game/GameAI.cs b/Game/GameAI.cs index 5ab235bc..77136319 100644 --- a/Game/GameAI.cs +++ b/Game/GameAI.cs @@ -119,9 +119,9 @@ public void OnNewPhase() Executor.OnNewPhase(); } - public void OnMove(int cardId, int previousControler, int previousLocation, int currentControler, int currentLocation) + public void OnMove(ClientCard card, int previousControler, int previousLocation, int currentControler, int currentLocation) { - Executor.OnMove(cardId, previousControler, previousLocation, currentControler, currentLocation); + Executor.OnMove(card, previousControler, previousLocation, currentControler, currentLocation); } /// @@ -157,6 +157,16 @@ public void OnChainEnd() Executor.OnChainEnd(); } + /// + /// Called when receiving annouce + /// + /// Player who announce. + /// Annouced info. + public void OnReceivingAnnouce(int player, int data) + { + Executor.OnReceivingAnnouce(player, data); + } + /// /// Called when the AI has to do something during the battle phase. /// diff --git a/Game/GameBehavior.cs b/Game/GameBehavior.cs index 9bf8eb05..ab24360d 100644 --- a/Game/GameBehavior.cs +++ b/Game/GameBehavior.cs @@ -347,6 +347,10 @@ private void OnHint(BinaryReader packet) { _select_hint = data; } + if (type == 4) // HINT_OPSELECTED + { + _ai.OnReceivingAnnouce(player, data); + } } private void OnStart(BinaryReader packet) @@ -354,6 +358,11 @@ private void OnStart(BinaryReader packet) int type = packet.ReadByte(); _duel.IsFirst = (type & 0xF) == 0; _duel.Turn = 0; + _duel.LastChainLocation = 0; + _duel.LastChainPlayer = -1; + _duel.LastChainTargets.Clear(); + _duel.LastSummonedCards.Clear(); + _duel.LastSummonPlayer = -1; int duel_rule = packet.ReadByte(); _ai.Duel.IsNewRule = (duel_rule >= 4); _ai.Duel.IsNewRule2020 = (duel_rule >= 5); @@ -653,7 +662,7 @@ private void OnMove(BinaryReader packet) } } - _ai.OnMove(cardId, previousControler, previousLocation, currentControler, currentLocation); + _ai.OnMove(card, previousControler, previousLocation, currentControler, currentLocation); } private void OnSwap(BinaryReader packet) diff --git a/WindBot.csproj b/WindBot.csproj index f2af022f..61125d4b 100644 --- a/WindBot.csproj +++ b/WindBot.csproj @@ -103,6 +103,7 @@ +