diff --git a/BotWrapper/bot.conf b/BotWrapper/bot.conf
index 7c276289..3e2d153f 100644
--- a/BotWrapper/bot.conf
+++ b/BotWrapper/bot.conf
@@ -189,11 +189,16 @@ Name=我太帅了 Deck=Brave Dialog=smart.zh-CN
水机百头龙凤凰人勇者卡组。
AI_LV3 SUPPORT_MASTER_RULE_2020
-!玻璃女巫
+!玻璃女巫-魔女术
Name=玻璃女巫 Deck=Witchcraft Dialog=verre.zh-CN
魔女术卡组。
AI_LV3 SUPPORT_MASTER_RULE_3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
+!玻璃女巫-救祓少女
+Name=玻璃女巫 Deck=Exosister Dialog=verre.zh-CN
+救祓少女卡组。
+AI_LV3 SUPPORT_MASTER_RULE_3 SUPPORT_MASTER_RULE_2020
+
!神数不神-刹帝利
Name=神数不神 Deck=Kashtira Dialog=Zefra.zh-CN
俱舍怒威族卡组。
diff --git a/Decks/AI_Exosister.ydk b/Decks/AI_Exosister.ydk
new file mode 100644
index 00000000..1e5c0fac
--- /dev/null
+++ b/Decks/AI_Exosister.ydk
@@ -0,0 +1,60 @@
+#created by ...
+#main
+37343995
+37343995
+37343995
+16889337
+16889337
+16889337
+16474916
+16474916
+16474916
+67972302
+67972302
+67972302
+79858629
+79858629
+43863925
+43863925
+43863925
+5352328
+5352328
+14558127
+14558127
+14558127
+23434538
+23434538
+23434538
+84211599
+84211599
+4408198
+24224830
+24224830
+77913594
+77913594
+77913594
+197042
+197042
+10045474
+10045474
+77891946
+77891946
+77891946
+#extra
+90448279
+59242457
+59242457
+9272381
+42741437
+42741437
+42741437
+78135071
+78135071
+41524885
+41524885
+46772449
+5530780
+58858807
+8728498
+!side
+74689476
diff --git a/ExecutorBase/Game/AI/DefaultExecutor.cs b/ExecutorBase/Game/AI/DefaultExecutor.cs
index 01a545da..e13d417d 100644
--- a/ExecutorBase/Game/AI/DefaultExecutor.cs
+++ b/ExecutorBase/Game/AI/DefaultExecutor.cs
@@ -117,6 +117,98 @@ protected class _CardId
public const int RoyalDecreel = 51452091;
public const int NaturiaBeast = 33198837;
public const int AntiSpellFragrance = 58921041;
+
+ 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;
+ public const int PerformapalBarokuriboh = 19050066;
+ public const int LabrynthArchfiend = 48745395;
+ public const int HarpiesPetDragonFearsomeFireBlast = 4991081;
+ public const int DynaHeroFurHire = 25123713;
+ public const int Hieracosphinx = 82260502;
+ public const int SpeedroidPassinglider = 26420373;
+ public const int TyrOfTheNordicChampions = 2333365;
+ public const int ValkyrianKnight = 99348756;
+ public const int Victoria = 75162696;
+ public const int MadolcheChouxvalier = 75363626;
+ public const int LadyOfD = 67511500;
+ public const int MermailAbysslung = 95466842;
+ public const int HarpiesPetBabyDragon = 6924874;
+ public const int HandHoldingGenie = 94535485;
+ public const int GolemDragon = 9666558;
+ public const int TwilightRoseKnight = 2986553;
+ public const int PerformapalThunderhino = 70458081;
+ public const int MiracleFlipper = 131182;
+ public const int Decoyroid = 25034083;
+ public const int AltergeistFifinellag = 12977245;
+ public const int BatterymanD = 55401221;
+ public const int Watthopper = 61380658;
+ public const int EgyptianGodSlime = 42166000;
+ public const int DinowrestlerChimeraTWrextle = 22900219;
+ public const int DinowrestlerGigaSpinosavate = 58672736;
+ public const int ScarredWarrior = 45298492;
+ public const int SharkFortress = 50449881;
+ public const int HeroicChampionClaivesolish = 97453744;
+ public const int GhostrickAlucard = 75367227;
+ public const int DinowrestlerKingTWrextle = 77967790;
+
+ public const int PerformapalMissDirector = 92932860;
+ public const int AncientWarriorsMasterfulSunMou = 40140448;
+ public const int AncientWarriorsVirtuousLiuXuan = 40428851;
+ public const int CommandKnight = 10375182;
+ public const int HunterOwl = 51962254;
+ public const int RokketRecharger = 5969957;
+ public const int EmissaryOfTheOasis = 6103294;
+ public const int Zuttomozaurus = 24454387;
+ public const int Otoshidamashi = 14957440;
+ public const int NaturiaMosquito = 17285476;
+ public const int RescueACEHydrant = 37617348;
+ public const int MeizenTheBattleNinja = 11825276;
+ public const int VindikiteRGenex = 73483491;
+ public const int PrincessCologne = 75574498;
+ public const int Number48ShadowLich = 1426714;
+ public const int PhantomToken = 1426715;
+ public const int DuelLinkDragonTheDuelDragon = 60025883;
+ public const int DuelDragonToken = 60025884;
+ public const int SeleneQueenOfTheMasterMagicians = 45819647;
+ public const int TheWingedDragonofRaSphereMode = 10000080;
+
+ public const int RockOfTheVanquisher = 28168628;
+ public const int SpiralDischarge = 29477860;
+ public const int GaiaTheDragonChampion = 66889139;
+ public const int CrusadiaVanguard = 55312487;
+ public const int GladiatorBeastDomitianus = 33652635;
+ public const int PatricianOfDarkness = 19153634;
+ public const int DictatorOfD = 66961194;
+
+ public const int NovoxTheSilenforcerDisciple = 25801745;
+ public const int SilenforcingBarrier = 98477480;
+ }
+
+ protected class _Setcode
+ {
+ public const int Watt = 0xe;
+ public const int Speedroid = 0x2016;
+ public const int EarthboundImmortal = 0x1021;
+ public const int Naturia = 0x2a;
+ public const int Nordic = 0x42;
+ public const int Harpie = 0x64;
+ public const int Madolche = 0x71;
+ public const int Ghostrick = 0x8d;
+ public const int OddEyes = 0x99;
+ public const int Performapal = 0x9f;
+ public const int BlueEyes = 0xdd;
+ public const int FurHire = 0x114;
+ public const int Altergeist = 0x103;
+ public const int Crusadia = 0x116;
+ public const int Endymion = 0x12a;
+ public const int AncientWarriors = 0x137;
+ public const int RescueACE = 0x18b;
+ public const int VanquishSoul = 0x195;
}
protected DefaultExecutor(GameAI ai, Duel duel)
@@ -126,6 +218,79 @@ 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.
+ ///
+ protected Dictionary> DefenderProtectRule = new Dictionary> {
+ {_CardId.BelialMarquisOfDarkness, defender => defender.IsFaceup()},
+ {_CardId.ChirubiméPrincessOfAutumnLeaves, defender => defender.HasRace(CardRace.Plant)},
+ {_CardId.PerformapalBarokuriboh, defender => true},
+ {_CardId.LabrynthArchfiend, defender => defender.HasRace(CardRace.Fiend) && !defender.IsCode(_CardId.LabrynthArchfiend)},
+ {_CardId.HarpiesPetDragonFearsomeFireBlast, defender => defender.Level <= 6 && defender.HasSetcode(_Setcode.Harpie)},
+ {_CardId.DynaHeroFurHire, defender => defender.HasSetcode(_Setcode.FurHire)},
+ {_CardId.Hieracosphinx, defender => defender.IsFacedown()},
+ {_CardId.SpeedroidPassinglider, defender => defender.HasSetcode(_Setcode.Speedroid)},
+ {_CardId.TyrOfTheNordicChampions, defender => defender.HasSetcode(_Setcode.Nordic)},
+ {_CardId.ValkyrianKnight, defender => defender.HasRace(CardRace.Warrior) && !defender.IsCode(_CardId.ValkyrianKnight)},
+ {_CardId.Victoria, defender => defender.HasRace(CardRace.Fairy)},
+ {_CardId.MadolcheChouxvalier, defender => defender.HasSetcode(_Setcode.Madolche) && !defender.IsCode(_CardId.MadolcheChouxvalier)},
+ {_CardId.LadyOfD, defender => defender.HasRace(CardRace.Dragon)},
+ {_CardId.MermailAbysslung, defender => defender.HasAttribute(CardAttribute.Water)},
+ {_CardId.HarpiesPetBabyDragon, defender => defender.HasSetcode(_Setcode.Harpie) && !defender.IsCode(_CardId.HarpiesPetBabyDragon)},
+ {_CardId.HandHoldingGenie, defender => true},
+ {_CardId.GolemDragon, defender => defender.HasRace(CardRace.Dragon)},
+ {_CardId.MaraudingCaptain, defender => defender.HasRace(CardRace.Warrior)},
+ {_CardId.TwilightRoseKnight, defender => defender.HasRace(CardRace.Plant)},
+ {_CardId.PerformapalThunderhino, defender => defender.HasSetcode(_Setcode.Performapal)},
+ {_CardId.MiracleFlipper, defender => defender.IsFaceup()},
+ {_CardId.Decoyroid, defender => defender.IsFaceup()},
+ {_CardId.DupeFrog, defender => true},
+ {_CardId.AltergeistFifinellag, defender => defender.HasSetcode(_Setcode.Altergeist)},
+ {_CardId.BatterymanD, defender => defender.HasRace(CardRace.Thunder) && !defender.IsCode(_CardId.BatterymanD)},
+ {_CardId.Watthopper, defender => defender.HasSetcode(_Setcode.Watt) && defender.IsFaceup()},
+
+ {_CardId.EgyptianGodSlime, defender => true},
+ {_CardId.DinowrestlerChimeraTWrextle, defender => true},
+ {_CardId.DinowrestlerGigaSpinosavate, defender => true},
+ {_CardId.ScarredWarrior, defender => defender.HasRace(CardRace.Warrior) && defender.IsFaceup()},
+ {_CardId.SharkFortress, defender => true},
+ {_CardId.HeroicChampionClaivesolish, defender => true},
+ {_CardId.GhostrickAlucard, defender => defender.HasSetcode(_Setcode.Ghostrick) || defender.IsFacedown()},
+ {_CardId.MekkKnightCrusadiaAstram, defender => true},
+ {_CardId.DinowrestlerKingTWrextle, defender => true}
+ };
+
+ ///
+ /// Defined:
+ /// if monster with KEY on field, and meet VALUE(monster, all monster), it cannot be targeted for attack.
+ ///
+ protected Dictionary, bool>> DefenderInvisbleRule = new Dictionary, bool>> {
+ {_CardId.UltimayaTzolkin, (defender, list) => list.Any(monster => !monster.Equals(defender) && monster.HasType(CardType.Synchro))},
+ {_CardId.PerformapalMissDirector, (defender, list) => list.Any(monster => monster.HasSetcode(_Setcode.OddEyes))},
+ {_CardId.AncientWarriorsMasterfulSunMou, (defender, list) => list.Any(monster => !monster.Equals(defender) && monster.HasSetcode(_Setcode.AncientWarriors))},
+ {_CardId.AncientWarriorsVirtuousLiuXuan, (defender, list) => list.Any(monster => !monster.Equals(defender) && monster.HasSetcode(_Setcode.AncientWarriors))},
+ {_CardId.CommandKnight, (defender, list) => list.Any(monster => !monster.Equals(defender))},
+ {_CardId.HunterOwl, (defender, list) => list.Any(monster => !monster.Equals(defender) && monster.HasAttribute(CardAttribute.Wind))},
+ {_CardId.RokketRecharger, (defender, list) => list.Any(monster => monster.IsExtraCard() && monster.HasAttribute(CardAttribute.Dark))},
+ {_CardId.EmissaryOfTheOasis, (defender, list) => list.Any(monster => monster.HasType(CardType.Normal) && monster.Level <= 3)},
+ {_CardId.Zuttomozaurus, (defender, list) => list.Any(monster => !monster.Equals(defender) && monster.HasRace(CardRace.Dinosaur))},
+ {_CardId.Otoshidamashi, (defender, list) => list.Any(monster => !monster.HasType(CardType.Tuner))},
+ {_CardId.NaturiaMosquito, (defender, list) => list.Any(monster => !monster.Equals(defender) && monster.HasSetcode(_Setcode.Naturia))},
+ {_CardId.RescueACEHydrant, (defender, list) => list.Any(monster => !monster.IsCode(_CardId.RescueACEHydrant) && monster.HasSetcode(_Setcode.RescueACE))},
+
+ {_CardId.MeizenTheBattleNinja, (defender, list) => list.Any(monster => monster.IsFacedown())},
+ {_CardId.VindikiteRGenex, (defender, list) => true},
+ {_CardId.PrincessCologne, (defender, list) => list.Any(monster => !monster.Equals(defender))},
+ {_CardId.Number48ShadowLich, (defender, list) => list.Any(monster => monster.IsCode(_CardId.PhantomToken))},
+ {_CardId.DuelLinkDragonTheDuelDragon, (defender, list) => list.Any(monster => monster.IsCode(_CardId.DuelDragonToken))},
+ {_CardId.SeleneQueenOfTheMasterMagicians, (defender, list) => list.Any(monster => monster.HasSetcode(_Setcode.Endymion))},
+
+ {_CardId.TheWingedDragonofRaSphereMode, (defender, list) => true}
+ };
+
///
/// Decide which card should the attacker attack.
///
@@ -225,7 +390,22 @@ public override bool OnPreBattleBetween(ClientCard attacker, ClientCard defender
}
}
- if (Enemy.HasInMonstersZone(_CardId.MekkKnightCrusadiaAstram, true) && !(defender).IsCode(_CardId.MekkKnightCrusadiaAstram))
+ 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;
+ if (DefenderInvisbleRule.TryGetValue(defender.Id, out defenderRule))
+ {
+ if (defenderRule(defender, Enemy.GetMonsters())) return false;
+ }
+ }
+
+ if (Enemy.GetMonsters().Any(monster => !monster.Equals(defender) && monster.IsCode(_CardId.HamonLordofStrikingThunder) && !monster.IsDisabled() && monster.IsDefense()))
+ return false;
+
+ if (defender.OwnTargets.Any(card => card.IsCode(_CardId.PhantomKnightsFogBlade) && !card.IsDisabled()))
return false;
if (Enemy.HasInMonstersZone(_CardId.DupeFrog, true) && !(defender).IsCode(_CardId.DupeFrog))
@@ -239,8 +419,11 @@ public override bool OnPreBattleBetween(ClientCard attacker, ClientCard defender
if (Enemy.GetMonsters().Any(monster => !monster.Equals(defender) && monster.IsCode(_CardId.HamonLordofStrikingThunder) && !monster.IsDisabled() && monster.IsDefense()))
return false;
+
+ if (defender.IsCode(_CardId.RescueACEHydrant) && !defender.IsDisabled() && Enemy.GetMonsters().Any(monster => monster.HasSetcode(_Setcode.RescueACE) && !monster.IsCode(_CardId.RescueACEHydrant)))
+ return false;
- if (defender.OwnTargets.Any(card => card.IsCode(_CardId.PhantomKnightsFogBlade) && !card.IsDisabled()))
+ if (Enemy.HasInSpellZone(_CardId.SilenforcingBarrier, true) && Enemy.HasInMonstersZone(_CardId.NovoxTheSilenforcerDisciple, faceUp: true) && !defender.HasType(CardType.Ritual))
return false;
return true;
@@ -788,16 +971,24 @@ protected bool DefaultOnBecomeTarget()
_CardId.BlackRoseDragon,
_CardId.JudgmentDragon,
_CardId.TopologicTrisbaena,
- _CardId.EvenlyMatched
+ _CardId.EvenlyMatched,
+ _CardId.DivineArsenalAAZEUS_SkyThunder
};
int[] destroyAllOpponentList =
{
_CardId.HarpiesFeatherDuster,
_CardId.DarkMagicAttack
};
+ int[] destroyAllOpponentSpellList =
+ {
+ _CardId.HarpiesFeatherDuster,
+ _CardId.DarkMagicAttack
+ };
if (Util.ChainContainsCard(destroyAllList)) return true;
- if (Enemy.HasInSpellZone(destroyAllOpponentList, true)) 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;
}
@@ -893,12 +1084,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())
@@ -929,7 +1119,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))
{
@@ -1177,5 +1368,71 @@ protected bool DefaultHonestEffect()
return Util.IsTurn1OrMain2();
}
+
+ ///
+ /// Always activate
+ ///
+ protected bool DefaultVaylantzWorld_ShinraBansho()
+ {
+ if (DefaultSpellWillBeNegated()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Select enemy's best monster
+ ///
+ protected bool DefaultVaylantzWorld_KonigWissen()
+ {
+ if (DefaultSpellWillBeNegated()) {
+ return false;
+ }
+
+ List monsters = Enemy.GetMonsters();
+ if (monsters.Count == 0) {
+ return false;
+ }
+
+ List targetList = new List();
+ List floodgateCards = monsters
+ .Where(card => card?.Data != null && card.IsFloodgate() && card.IsFaceup() && !card.IsShouldNotBeTarget())
+ .OrderByDescending(card => card.Attack).ToList();
+ List dangerousCards = monsters
+ .Where(card => card?.Data != null && card.IsMonsterDangerous() && card.IsFaceup() && !card.IsShouldNotBeTarget())
+ .OrderByDescending(card => card.Attack).ToList();
+ List attackOrderedCards = monsters
+ .Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && card.IsShouldNotBeTarget())
+ .OrderByDescending(card => card.Attack).ToList();
+
+ targetList.AddRange(floodgateCards);
+ targetList.AddRange(dangerousCards);
+ targetList.AddRange(attackOrderedCards);
+
+ if (targetList?.Count > 0)
+ {
+ AI.SelectCard(targetList);
+ return true;
+ }
+
+ return false;
+ }
+
+ public override void OnReceivingAnnouce(int player, long data)
+ {
+ if (player == 1 && data == Util.GetStringId(_CardId.LightningStorm, 0) || data == Util.GetStringId(_CardId.LightningStorm, 1))
+ {
+ lightningStormOption = (int)(data - Util.GetStringId(_CardId.LightningStorm, 0));
+ }
+
+ base.OnReceivingAnnouce(player, data);
+ }
+
+ public override void OnChainEnd()
+ {
+ lightningStormOption = -1;
+ base.OnChainEnd();
+ }
}
}
diff --git a/ExecutorBase/Game/AI/Enums/FusionSpell.cs b/ExecutorBase/Game/AI/Enums/FusionSpell.cs
index b4859b55..e9def396 100644
--- a/ExecutorBase/Game/AI/Enums/FusionSpell.cs
+++ b/ExecutorBase/Game/AI/Enums/FusionSpell.cs
@@ -55,5 +55,36 @@ public enum FusionSpell
FragmentFusion = 72029628,
NecroFusion = 81223446,
PredaplantVerteAnaconda = 70369116,
+
+ DreamMirrorofChaos = 98570539,
+ PlunderPatrollShipshapeShipsShipping = 44227727,
+ FireFormationIngen = 29143457,
+ ParametalfoesFusion = 58549532,
+ ReadyFusion = 63854005,
+ BrandedinWhite = 34995106,
+ BrandedinRed = 82738008,
+ FaceCardFusion = 29062925,
+ MyutantFusion = 42577802,
+ MyutantCry = 31855260,
+ FallenOfAlbaz = 68468459,
+ GreaterPolymerization = 7614732,
+ UltimateFusion = 71143015,
+ BrandedFusion = 44362883,
+ GhostFusion = 35705817,
+ WitchcrafterConfusionConfession = 35098357,
+ BrandedBanishment = 6763530,
+ DinomorphiaDomain = 26631975,
+ DinomorphiaFrenzy = 78420796,
+ SouloftheSupremeKing = 92428405,
+ InstantContact = 16169772,
+ ScatterFusion = 40597694,
+ FavoriteContact = 75047173,
+ AmazonessSecretArts = 86758746,
+ DarkWorldAccession = 65956182,
+ BeetrooperLanding = 13234975,
+ FusionReproduction = 43331750,
+ ChimeraFusion = 63136489,
+ HarmonicSynchroFusion = 7473735,
+ SouloftheSupremeCelestialKing = 76840111
}
}
diff --git a/ExecutorBase/Game/AI/Executor.cs b/ExecutorBase/Game/AI/Executor.cs
index 7b8b36f8..0e8bf6cd 100644
--- a/ExecutorBase/Game/AI/Executor.cs
+++ b/ExecutorBase/Game/AI/Executor.cs
@@ -22,6 +22,7 @@ public abstract class Executor
protected ExecutorType Type { get; private set; }
protected ClientCard Card { get; private set; }
protected long ActivateDescription { get; private set; }
+ protected int CurrentTiming { get; private set; }
protected ClientField Bot { get; private set; }
protected ClientField Enemy { get; private set; }
@@ -97,10 +98,21 @@ public virtual void OnChaining(int player, ClientCard card)
// For overriding
}
+ public virtual void OnChainSolved(int chainIndex)
+ {
+ // For overriding
+ }
+
public virtual void OnChainEnd()
{
// For overriding
}
+
+ public virtual void OnReceivingAnnouce(int player, long data)
+ {
+ // For overriding
+ }
+
public virtual void OnNewPhase()
{
// Some AI need do something on new phase
@@ -115,6 +127,11 @@ public virtual void OnDraw(int player)
// Some AI need do something on draw
}
+ public virtual void OnMove(ClientCard card, int previousControler, int previousLocation, int currentControler, int currentLocation)
+ {
+ // Some AI need do something on card's moving
+ }
+
public virtual IList OnSelectCard(IList cards, int min, int max, long hint, bool cancelable)
{
// For overriding
@@ -174,6 +191,23 @@ public virtual void OnSelectChain(IList cards)
return;
}
+ public virtual bool OnSelectYesNo(int desc)
+ {
+ return true;
+ }
+
+ public virtual int OnSelectOption(IList options)
+ {
+ return -1;
+ }
+
+ public virtual int OnSelectPlace(int cardId, int player, CardLocation location, int available)
+ {
+ // For overriding
+ return 0;
+ }
+
+
public virtual bool OnSelectYesNo(long desc)
{
return true;
@@ -236,11 +270,12 @@ public void SetBattle(BattlePhase battle)
///
/// Set global variables Type, Card, ActivateDescription for Executor
///
- public void SetCard(ExecutorType type, ClientCard card, long description)
+ public void SetCard(ExecutorType type, ClientCard card, long description, int timing = -1)
{
Type = type;
Card = card;
ActivateDescription = description;
+ CurrentTiming = timing;
}
///
diff --git a/ExecutorBase/Game/AI/HintMsg.cs b/ExecutorBase/Game/AI/HintMsg.cs
index 98e723a4..a781df42 100644
--- a/ExecutorBase/Game/AI/HintMsg.cs
+++ b/ExecutorBase/Game/AI/HintMsg.cs
@@ -56,6 +56,13 @@ public static class HintMsg
DisableZone = 570,
ToZone = 571,
Counter = 572,
- Negate = 575;
+ Disable = 573,
+ OperateCard = 574,
+ Negate = 575,
+ RITUAL = 1057,
+ FUSION = 1056,
+ SYNCHRO = 1063,
+ XYZ = 1073,
+ PENDULUM = 1074;
}
}
diff --git a/ExecutorBase/Game/Duel.cs b/ExecutorBase/Game/Duel.cs
index 8a4ccaeb..806ebc29 100644
--- a/ExecutorBase/Game/Duel.cs
+++ b/ExecutorBase/Game/Duel.cs
@@ -18,13 +18,17 @@ public class Duel
public BattlePhase BattlePhase { get; set; }
public int LastChainPlayer { get; set; }
+ public CardLocation LastChainLocation { get; set; }
public IList CurrentChain { get; set; }
public IList ChainTargets { get; set; }
+ public IList LastChainTargets { get; set; }
public IList ChainTargetOnly { get; set; }
public int LastSummonPlayer { get; set; }
public IList SummoningCards { get; set; }
public IList LastSummonedCards { get; set; }
public bool MainPhaseEnd { get; set; }
+ public int SolvingChainIndex { get; set; }
+ public IList NegatedChainIndexList { get; set; }
public Duel()
{
@@ -32,9 +36,11 @@ public Duel()
Fields[0] = new ClientField();
Fields[1] = new ClientField();
LastChainPlayer = -1;
+ LastChainLocation = 0;
MainPhaseEnd = false;
CurrentChain = new List();
ChainTargets = new List();
+ LastChainTargets = new List();
ChainTargetOnly = new List();
LastSummonPlayer = -1;
SummoningCards = new List();
@@ -203,5 +209,16 @@ public int GetLocalPlayer(int player)
{
return IsFirst ? player : 1 - player;
}
+
+ public ClientCard GetCurrentSolvingChainCard()
+ {
+ if (SolvingChainIndex == 0 || SolvingChainIndex > CurrentChain.Count) return null;
+ return CurrentChain[SolvingChainIndex - 1];
+ }
+
+ public bool IsCurrentSolvingChainNegated()
+ {
+ return SolvingChainIndex > 0 && NegatedChainIndexList.Contains(SolvingChainIndex);
+ }
}
}
diff --git a/ExecutorBase/Game/GameAI.cs b/ExecutorBase/Game/GameAI.cs
index 267d8def..52d39a8d 100644
--- a/ExecutorBase/Game/GameAI.cs
+++ b/ExecutorBase/Game/GameAI.cs
@@ -120,6 +120,11 @@ public void OnNewPhase()
Executor.OnNewPhase();
}
+ public void OnMove(ClientCard card, int previousControler, int previousLocation, int currentControler, int currentLocation)
+ {
+ Executor.OnMove(card, previousControler, previousLocation, currentControler, currentLocation);
+ }
+
///
/// Called when the AI got attack directly.
///
@@ -148,6 +153,16 @@ public void OnChainEnd()
Executor.OnChainEnd();
}
+ ///
+ /// Called when receiving annouce
+ ///
+ /// Player who announce.
+ /// Annouced info.
+ public void OnReceivingAnnouce(int player, long data)
+ {
+ Executor.OnReceivingAnnouce(player, data);
+ }
+
///
/// Called when the AI has to do something during the battle phase.
///
diff --git a/Game/AI/Decks/ExosisterExecutor.cs b/Game/AI/Decks/ExosisterExecutor.cs
new file mode 100644
index 00000000..587b8db5
--- /dev/null
+++ b/Game/AI/Decks/ExosisterExecutor.cs
@@ -0,0 +1,2992 @@
+using YGOSharp.OCGWrapper;
+using YGOSharp.OCGWrapper.Enums;
+using System.Collections.Generic;
+using WindBot;
+using WindBot.Game;
+using WindBot.Game.AI;
+using System.Linq;
+using System;
+
+namespace WindBot.Game.AI.Decks
+{
+ [Deck("Exosister", "AI_Exosister")]
+
+ class ExosisterExecutor : DefaultExecutor
+ {
+ public class CardId
+ {
+ public const int ExosisterElis = 16474916;
+ public const int ExosisterStella = 43863925;
+ public const int ExosisterIrene = 79858629;
+ public const int ExosisterSophia = 5352328;
+ public const int ExosisterMartha = 37343995;
+ public const int Aratama = 16889337;
+ public const int Sakitama = 67972302;
+ // _CardId.MaxxC = 23434538;
+ // _CardId.AshBlossom = 14558127;
+
+ public const int ExosisterPax = 77913594;
+ public const int ExosisterArment = 4408198;
+ public const int PotofExtravagance = 84211599;
+ // _CardId.CalledByTheGrave = 24224830;
+
+ public const int ExosisterVadis = 77891946;
+ public const int ExosisterReturnia = 197042;
+ // _CardId.InfiniteImpermanence = 10045474;
+
+ public const int ExosisterMikailis = 42741437;
+ public const int ExosisterKaspitell = 78135071;
+ public const int ExosisterGibrine = 5530780;
+ public const int ExosisterAsophiel = 41524885;
+ public const int ExosistersMagnifica = 59242457;
+ public const int TellarknightConstellarCaduceus = 58858807;
+ public const int StellarknightConstellarDiamond = 9272381;
+ public const int DivineArsenalAAZEUS_SkyThunder = 90448279;
+ public const int DonnerDaggerFurHire = 8728498;
+ // _CardId.EvilswarmExcitonKnight = 46772449;
+
+ 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 DimensionShifter = 91800273;
+ }
+
+ public ExosisterExecutor(GameAI ai, Duel duel)
+ : base(ai, duel)
+ {
+ // trigger
+ AddExecutor(ExecutorType.Activate, CardId.ExosistersMagnifica, ExosistersMagnificaActivateTrigger);
+
+ // quick effect
+ AddExecutor(ExecutorType.Activate, CardId.ExosisterMikailis, ExosisterMikailisActivate);
+ AddExecutor(ExecutorType.Activate, CardId.ExosistersMagnifica, ExosistersMagnificaActivateBanish);
+ AddExecutor(ExecutorType.Activate, CardId.ExosisterReturnia, ExosisterReturniaActivate);
+ AddExecutor(ExecutorType.Activate, CardId.ExosisterVadis, ExosisterVadisActivate);
+ AddExecutor(ExecutorType.Activate, _CardId.InfiniteImpermanence, InfiniteImpermanenceActivate);
+ AddExecutor(ExecutorType.Activate, CardId.StellarknightConstellarDiamond);
+ AddExecutor(ExecutorType.Activate, _CardId.AshBlossom, AshBlossomActivate);
+ AddExecutor(ExecutorType.Activate, _CardId.CalledByTheGrave, CalledbytheGraveActivate);
+ AddExecutor(ExecutorType.Activate, DefaultExosisterTransform);
+ AddExecutor(ExecutorType.Activate, CardId.ExosisterArment, ExosisterArmentActivate);
+
+ // free chain
+ AddExecutor(ExecutorType.Activate, _CardId.MaxxC, MaxxCActivate);
+
+ // search
+ AddExecutor(ExecutorType.Activate, CardId.PotofExtravagance, PotofExtravaganceActivate);
+
+ // field effect
+ AddExecutor(ExecutorType.Activate, CardId.Aratama);
+ AddExecutor(ExecutorType.Activate, CardId.DonnerDaggerFurHire, DonnerDaggerFurHireActivate);
+ AddExecutor(ExecutorType.Activate, CardId.ExosisterKaspitell, ExosisterKaspitellActivate);
+ AddExecutor(ExecutorType.Activate, CardId.ExosisterGibrine, ExosisterGibrineActivate);
+ AddExecutor(ExecutorType.Activate, CardId.ExosisterAsophiel, ExosisterAsophielActivate);
+
+ AddExecutor(ExecutorType.Activate, CardId.ExosisterSophia, ExosisterSophiaActivate);
+ AddExecutor(ExecutorType.Activate, CardId.ExosisterIrene, ExosisterIreneActivate);
+ AddExecutor(ExecutorType.Activate, CardId.ExosisterStella, ExosisterStellaActivate);
+
+ // addition monster summmon
+ AddExecutor(ExecutorType.Activate, CardId.ExosisterElis, ExosisterElisActivate);
+ AddExecutor(ExecutorType.Activate, CardId.Sakitama, SakitamaActivate);
+ AddExecutor(ExecutorType.Activate, CardId.ExosisterPax, ExosisterPaxActivate);
+ AddExecutor(ExecutorType.Activate, CardId.ExosisterStella, ExosisterStellaSecondActivate);
+
+ // xyz summon
+ AddExecutor(ExecutorType.SpSummon, CardId.StellarknightConstellarDiamond);
+ AddExecutor(ExecutorType.SpSummon, CardId.DonnerDaggerFurHire, DonnerDaggerFurHireSpSummonCheck);
+ AddExecutor(ExecutorType.SpSummon, CardId.ExosisterMikailis, ExosisterMikailisAdvancedSpSummonCheck);
+ AddExecutor(ExecutorType.SpSummon, CardId.ExosisterKaspitell, ExosisterKaspitellAdvancedSpSummonCheck);
+
+ AddExecutor(ExecutorType.SpSummon, CardId.ExosisterKaspitell, ExosisterKaspitellSpSummonCheck);
+ AddExecutor(ExecutorType.SpSummon, CardId.ExosisterMikailis, ExosisterMikailisSpSummonCheck);
+ AddExecutor(ExecutorType.SpSummon, CardId.TellarknightConstellarCaduceus, TellarknightConstellarCaduceusSpSummonCheck);
+
+ AddExecutor(ExecutorType.SpSummon, CardId.ExosistersMagnifica, ExosistersMagnificaSpSummonCheck);
+
+ AddExecutor(ExecutorType.SpSummon, _CardId.EvilswarmExcitonKnight, DefaultEvilswarmExcitonKnightSummon);
+ AddExecutor(ExecutorType.Activate, _CardId.EvilswarmExcitonKnight, DefaultEvilswarmExcitonKnightEffect);
+
+ // normal summon for xyz(avoiding MaxxC)
+ AddExecutor(ExecutorType.Summon, CardId.ExosisterStella, ExosisterAvoidMaxxCSummonCheck);
+ AddExecutor(ExecutorType.Summon, CardId.ExosisterSophia, ExosisterAvoidMaxxCSummonCheck);
+ AddExecutor(ExecutorType.Summon, CardId.ExosisterIrene, ExosisterAvoidMaxxCSummonCheck);
+ AddExecutor(ExecutorType.Summon, CardId.ExosisterElis, ExosisterAvoidMaxxCSummonCheck);
+
+ // activate martha
+ AddExecutor(ExecutorType.Activate, CardId.ExosisterMartha, ExosisterMarthaActivate);
+
+ // normal summon for xyz
+ AddExecutor(ExecutorType.Summon, CardId.ExosisterStella, ExosisterStellaSummonCheck);
+ AddExecutor(ExecutorType.Summon, CardId.Aratama, AratamaSummonCheck);
+ AddExecutor(ExecutorType.Summon, ExosisterForElisSummonCheck);
+ AddExecutor(ExecutorType.Summon, ForSakitamaSummonCheck);
+ AddExecutor(ExecutorType.Summon, CardId.ExosisterIrene, ExosisterIreneSummonCheck);
+ AddExecutor(ExecutorType.Summon, Level4SummonCheck);
+ AddExecutor(ExecutorType.Summon, ExosisterForArmentSummonCheck);
+ AddExecutor(ExecutorType.Summon, ForDonnerSummonCheck);
+
+ AddExecutor(ExecutorType.Activate, CardId.ExosisterPax, ExosisterPaxActivateForEndSearch);
+
+ // other
+ AddExecutor(ExecutorType.Repos, DefaultMonsterRepos);
+ AddExecutor(ExecutorType.SpellSet, SpellSetCheck);
+ }
+
+ const int SetcodeTimeLord = 0x4a;
+ const int SetcodeShadoll = 0x9d;
+ const int SetcodeInferoid = 0xbb;
+ const int SetcodeOrcust = 0x11b;
+ const int SetcodeExosister = 0x172;
+ const int SetcodeTearlaments = 0x181;
+ List SetcodeForDiamond = new List { SetcodeShadoll, SetcodeInferoid, SetcodeTearlaments };
+
+ List affectGraveCardIdList = new List{
+ 71344451, 40975243, 87746184, 70534340, 45906428, 71490127, 3659803, 12071500, 6077601, 11827244, 95238394, 81223446, 40003819,
+ 72490637, 21011044, 59419719, 14735698, 45410988
+ };
+
+ Dictionary> DeckCountTable = new Dictionary>{
+ {3, new List { CardId.ExosisterElis, CardId.ExosisterStella, CardId.ExosisterMartha, CardId.Aratama, CardId.Sakitama,
+ _CardId.MaxxC, _CardId.AshBlossom, CardId.ExosisterPax, CardId.ExosisterVadis }},
+ {2, new List { CardId.ExosisterIrene, CardId.ExosisterSophia, CardId.PotofExtravagance, _CardId.CalledByTheGrave,
+ CardId.ExosisterReturnia, _CardId.InfiniteImpermanence }},
+ {1, new List { CardId.ExosisterArment }},
+ };
+ Dictionary ExosisterMentionTable = new Dictionary{
+ {CardId.ExosisterElis, CardId.ExosisterStella}, {CardId.ExosisterStella, CardId.ExosisterElis},
+ {CardId.ExosisterIrene, CardId.ExosisterSophia}, {CardId.ExosisterSophia, CardId.ExosisterIrene},
+ {CardId.ExosisterMartha, CardId.ExosisterElis}
+ };
+ List ExosisterSpellTrapList = new List { CardId.ExosisterPax, CardId.ExosisterArment, CardId.ExosisterVadis, CardId.ExosisterReturnia };
+
+ Dictionary calledbytheGraveCount = new Dictionary();
+ bool enemyActivateMaxxC = false;
+ bool enemyActivateLockBird = false;
+ bool enemyMoveGrave = false;
+ bool paxCallToField = false;
+ List infiniteImpermanenceList = new List();
+
+ bool summoned = false;
+ bool elisEffect1Activated = false;
+ bool stellaEffect1Activated = false;
+ bool irenaEffect1Activated = false;
+ bool sophiaEffect1Activated = false;
+ bool marthaEffect1Activated = false;
+ bool mikailisEffect1Activated = false;
+ bool mikailisEffect3Activated = false;
+ bool kaspitellEffect1Activated = false;
+ bool kaspitellEffect3Activated = false;
+ bool gibrineEffect1Activated = false;
+ bool gibrineEffect3Activated = false;
+ bool asophielEffect1Activated = false;
+ bool asophielEffect3Activated = false;
+ bool sakitamaEffect1Activated = false;
+ List exosisterTransformEffectList = new List();
+ List oncePerTurnEffectActivatedList = new List();
+ List activatedMagnificaList = new List();
+ List targetedMagnificaList = new List();
+ List transformDestList = new List();
+ List spSummonThisTurn = new List();
+ bool potActivate = false;
+ List removeChosenList = new List();
+
+ ///
+ /// Shuffle List and return a random-order card list
+ ///
+ public List ShuffleCardList(List list)
+ {
+ List result = list;
+ int n = result.Count;
+ while (n-- > 1)
+ {
+ int index = Program.Rand.Next(n + 1);
+ ClientCard temp = result[index];
+ result[index] = result[n];
+ result[n] = temp;
+ }
+ return result;
+ }
+
+ public ClientCard GetProblematicEnemyMonster(int attack = 0, bool canBeTarget = false)
+ {
+ List floodagateList = Enemy.GetMonsters().Where(c => c?.Data != null &&
+ c.IsFloodgate() && c.IsFaceup() && (!canBeTarget || !c.IsShouldNotBeTarget())).ToList();
+ if (floodagateList.Count > 0)
+ {
+ floodagateList.Sort(CardContainer.CompareCardAttack);
+ floodagateList.Reverse();
+ return floodagateList[0];
+ }
+
+ List dangerList = Enemy.MonsterZone.Where(c => c?.Data != null &&
+ c.IsMonsterDangerous() && c.IsFaceup() && (!canBeTarget || !c.IsShouldNotBeTarget())).ToList();
+ if (dangerList.Count > 0)
+ {
+ dangerList.Sort(CardContainer.CompareCardAttack);
+ dangerList.Reverse();
+ return dangerList[0];
+ }
+
+ List invincibleList = Enemy.MonsterZone.Where(c => c?.Data != null &&
+ c.IsMonsterInvincible() && c.IsFaceup() && (!canBeTarget || !c.IsShouldNotBeTarget())).ToList();
+ if (invincibleList.Count > 0)
+ {
+ invincibleList.Sort(CardContainer.CompareCardAttack);
+ invincibleList.Reverse();
+ return invincibleList[0];
+ }
+
+ if (attack == 0)
+ attack = Util.GetBestAttack(Bot);
+ List betterList = Enemy.MonsterZone.GetMonsters()
+ .Where(card => card.GetDefensePower() >= attack && card.IsAttack() && (!canBeTarget || !card.IsShouldNotBeTarget())).ToList();
+ if (betterList.Count > 0)
+ {
+ betterList.Sort(CardContainer.CompareCardAttack);
+ betterList.Reverse();
+ return betterList[0];
+ }
+ return null;
+ }
+
+ public ClientCard GetProblematicEnemyCard(bool canBeTarget = false)
+ {
+ List floodagateList = Enemy.MonsterZone.Where(c => c?.Data != null && !removeChosenList.Contains(c) &&
+ c.IsFloodgate() && c.IsFaceup() && (!canBeTarget || !c.IsShouldNotBeTarget())).ToList();
+ if (floodagateList.Count > 0)
+ {
+ floodagateList.Sort(CardContainer.CompareCardAttack);
+ floodagateList.Reverse();
+ return floodagateList[0];
+ }
+
+ List problemEnemySpellList = Enemy.SpellZone.Where(c => c?.Data != null && !removeChosenList.Contains(c)
+ && c.IsFloodgate() && c.IsFaceup() && (!canBeTarget || !c.IsShouldNotBeTarget())).ToList();
+ if (problemEnemySpellList.Count > 0)
+ {
+ return ShuffleCardList(problemEnemySpellList)[0];
+ }
+
+ List dangerList = Enemy.MonsterZone.Where(c => c?.Data != null && !removeChosenList.Contains(c)
+ && c.IsMonsterDangerous() && c.IsFaceup() && (!canBeTarget || !c.IsShouldNotBeTarget())).ToList();
+ if (dangerList.Count > 0
+ && (Duel.Player == 0 || (Duel.Phase > DuelPhase.Main1 && Duel.Phase < DuelPhase.Main2)))
+ {
+ dangerList.Sort(CardContainer.CompareCardAttack);
+ dangerList.Reverse();
+ return dangerList[0];
+ }
+
+ List invincibleList = Enemy.MonsterZone.Where(c => c?.Data != null && !removeChosenList.Contains(c)
+ && c.IsMonsterInvincible() && c.IsFaceup() && (!canBeTarget || !c.IsShouldNotBeTarget())).ToList();
+ if (invincibleList.Count > 0)
+ {
+ invincibleList.Sort(CardContainer.CompareCardAttack);
+ invincibleList.Reverse();
+ return invincibleList[0];
+ }
+
+ List enemyMonsters = Enemy.GetMonsters().Where(c => !removeChosenList.Contains(c)).ToList();
+ if (enemyMonsters.Count > 0)
+ {
+ enemyMonsters.Sort(CardContainer.CompareCardAttack);
+ enemyMonsters.Reverse();
+ foreach (ClientCard target in enemyMonsters)
+ {
+ if (target.HasType(CardType.Fusion) || target.HasType(CardType.Ritual) || target.HasType(CardType.Synchro) || target.HasType(CardType.Xyz) || (target.HasType(CardType.Link) && target.LinkCount >= 2))
+ {
+ if (!canBeTarget || !(target.IsShouldNotBeTarget() || target.IsShouldNotBeMonsterTarget())) return target;
+ }
+ }
+ }
+
+ List spells = Enemy.GetSpells().Where(c => c.IsFaceup() && !removeChosenList.Contains(c)
+ && (c.HasType(CardType.Equip) || c.HasType(CardType.Pendulum) || c.HasType(CardType.Field) || c.HasType(CardType.Continuous)))
+ .ToList();
+ if (spells.Count > 0)
+ {
+ return ShuffleCardList(spells)[0];
+ }
+
+ return null;
+ }
+
+ public ClientCard GetBestEnemyMonster(bool onlyFaceup = false, bool canBeTarget = false)
+ {
+ ClientCard card = GetProblematicEnemyMonster(0, canBeTarget);
+ if (card != null)
+ return card;
+
+ card = Enemy.MonsterZone.GetHighestAttackMonster(canBeTarget);
+ if (card != null)
+ return card;
+
+ List monsters = Enemy.GetMonsters();
+
+ // after GetHighestAttackMonster, the left monsters must be face-down.
+ if (monsters.Count > 0 && !onlyFaceup)
+ return ShuffleCardList(monsters)[0];
+
+ return null;
+ }
+
+ public ClientCard GetBestEnemySpell(bool onlyFaceup = false, bool canBeTarget = false)
+ {
+ List problemEnemySpellList = Enemy.SpellZone.Where(c => c?.Data != null
+ && c.IsFloodgate() && c.IsFaceup() && (!canBeTarget || !c.IsShouldNotBeTarget())).ToList();
+ if (problemEnemySpellList.Count > 0)
+ {
+ return ShuffleCardList(problemEnemySpellList)[0];
+ }
+
+ List spells = Enemy.GetSpells().Where(card => !(card.IsFaceup() && card.IsCode(_CardId.EvenlyMatched))).ToList();
+
+ List faceUpList = spells.Where(ecard => ecard.IsFaceup() &&
+ (ecard.HasType(CardType.Continuous) || ecard.HasType(CardType.Field) || ecard.HasType(CardType.Pendulum))).ToList();
+ if (faceUpList.Count > 0)
+ {
+ return ShuffleCardList(faceUpList)[0];
+ }
+
+ if (spells.Count > 0 && !onlyFaceup)
+ {
+ return ShuffleCardList(spells)[0];
+ }
+
+ return null;
+ }
+
+ public ClientCard GetBestEnemyCard(bool onlyFaceup = false, bool canBeTarget = false, bool checkGrave = false)
+ {
+ ClientCard card = GetBestEnemyMonster(onlyFaceup, canBeTarget);
+ if (card != null)
+ {
+ return card;
+ }
+
+ card = GetBestEnemySpell(onlyFaceup, canBeTarget);
+ if (card != null)
+ {
+ return card;
+ }
+
+ if (checkGrave && Enemy.Graveyard.Count > 0)
+ {
+ List graveMonsterList = Enemy.Graveyard.GetMatchingCards(c => c.IsMonster()).ToList();
+ if (graveMonsterList.Count > 0)
+ {
+ graveMonsterList.Sort(CardContainer.CompareCardAttack);
+ graveMonsterList.Reverse();
+ return graveMonsterList[0];
+ }
+ return ShuffleCardList(Enemy.Graveyard.ToList())[0];
+ }
+
+ return null;
+ }
+
+ ///
+ /// 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;
+ }
+
+ ///
+ /// Check negated turn count of id
+ ///
+ public int CheckCalledbytheGrave(int id)
+ {
+ if (!calledbytheGraveCount.ContainsKey(id))
+ {
+ return 0;
+ }
+ return calledbytheGraveCount[id];
+ }
+
+ public void CheckEnemyMoveGrave()
+ {
+ if (Duel.LastChainPlayer == 1)
+ {
+ ClientCard card = Util.GetLastChainCard();
+ if (Duel.LastChainLocation == CardLocation.Grave && card.Location == CardLocation.Grave)
+ {
+ Logger.DebugWriteLine("===Exosister: enemy activate effect from GY.");
+ enemyMoveGrave = true;
+ }
+ else if (affectGraveCardIdList.Contains(card.Id))
+ {
+ Logger.DebugWriteLine("===Exosister: enemy activate effect that affect GY.");
+ enemyMoveGrave = true;
+ }
+ else
+ {
+ foreach (ClientCard targetCard in Duel.LastChainTargets)
+ {
+ if (targetCard.Location == CardLocation.Grave)
+ {
+ Logger.DebugWriteLine("===Exosister: enemy target cards of GY.");
+ enemyMoveGrave = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Check exosister's relative card. 0 for error.
+ ///
+ public int CheckExosisterMentionCard(int id)
+ {
+ if (!ExosisterMentionTable.ContainsKey(id))
+ {
+ return 0;
+ }
+ return ExosisterMentionTable[id];
+ }
+
+ ///
+ /// 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;
+ return true;
+ }
+
+ ///
+ /// Check whether negate opposite's effect and clear flag
+ ///
+ public void CheckDeactiveFlag()
+ {
+ if (Util.GetLastChainCard() != null && Duel.LastChainPlayer == 1)
+ {
+ if (Util.GetLastChainCard().IsCode(_CardId.MaxxC))
+ {
+ enemyActivateMaxxC = false;
+ }
+ if (Util.GetLastChainCard().IsCode(_CardId.LockBird))
+ {
+ enemyActivateLockBird = false;
+ }
+ }
+ }
+
+ ///
+ /// Check whether opposite use Maxx-C, and thus make less operation.
+ ///
+ public bool CheckLessOperation()
+ {
+ if (!enemyActivateMaxxC)
+ {
+ return false;
+ }
+ return CheckAtAdvantage();
+ }
+
+ ///
+ /// Check whether bot is at advantage.
+ ///
+ public bool CheckAtAdvantage()
+ {
+ if (GetProblematicEnemyMonster() == null && Bot.GetMonsters().Any(card => card.IsFaceup()))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Check whether bot is in danger and need to summon monster to defense.
+ ///
+ public bool CheckInDanger()
+ {
+ if (Duel.Phase > DuelPhase.Main1 && Duel.Phase < DuelPhase.Main2)
+ {
+ int totalAtk = 0;
+ foreach (ClientCard m in Enemy.GetMonsters())
+ {
+ if (m.IsAttack() && !m.Attacked) totalAtk += m.Attack;
+ }
+ if (totalAtk >= Bot.LifePoints) return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Check whether can be used for xyz summon.
+ ///
+ public bool CheckAbleForXyz(ClientCard card)
+ {
+ return card.IsFaceup() && !card.HasType(CardType.Xyz) && !card.HasType(CardType.Link) && !card.HasType(CardType.Token) && card.Level == 4;
+ }
+
+ ///
+ /// Check whether bot can activate martha.
+ ///
+ public bool CheckMarthaActivatable()
+ {
+ return !marthaEffect1Activated && CheckCalledbytheGrave(CardId.ExosisterMartha) == 0 && CheckRemainInDeck(CardId.ExosisterElis) > 0
+ && !Bot.GetMonsters().Any(card => card.IsFacedown() || !card.HasType(CardType.Xyz));
+ }
+
+ ///
+ /// check enemy's dangerous card in grave
+ ///
+ public List CheckDangerousCardinEnemyGrave(bool onlyMonster = false)
+ {
+ List result = Enemy.Graveyard.GetMatchingCards(card =>
+ (!onlyMonster || card.IsMonster()) && card.HasSetcode(SetcodeOrcust)).ToList();
+ return result;
+ }
+
+ ///
+ /// Whether spell or trap will be negate. If so, return true.
+ ///
+ /// is counter trap
+ /// check target
+ ///
+ public bool SpellNegatable(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())
+ {
+ if (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)
+ {
+ if (Card.IsSpell() || Card.IsTrap())
+ {
+ if (SpellNegatable()) return true;
+ }
+ if (CheckCalledbytheGrave(Card.Id) > 0)
+ {
+ return true;
+ }
+ if (Card.IsMonster() && Card.Location == CardLocation.MonsterZone && Card.IsDefense())
+ {
+ if (Enemy.MonsterZone.GetFirstMatchingFaceupCard(card => card.IsCode(CardId.Number41BagooskatheTerriblyTiredTapir) && card.IsDefense() && !card.IsDisabled()) != null
+ || Bot.MonsterZone.GetFirstMatchingFaceupCard(card => card.IsCode(CardId.Number41BagooskatheTerriblyTiredTapir) && card.IsDefense() && !card.IsDisabled()) != null)
+ {
+ return true;
+ }
+ }
+ if (disablecheck)
+ {
+ return Card.IsDisabled();
+ }
+ return false;
+ }
+
+ ///
+ /// 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)
+ {
+ List list = new List { 0, 1, 2, 3, 4 };
+ int n = list.Count;
+ while (n-- > 1)
+ {
+ int index = Program.Rand.Next(n + 1);
+ int temp = list[index];
+ list[index] = list[n];
+ list[n] = temp;
+ }
+ foreach (int seq in list)
+ {
+ int zone = (int)System.Math.Pow(2, 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;
+ AI.SelectPlace(zone);
+ return;
+ };
+ }
+ AI.SelectPlace(0);
+ }
+
+ public void SelectXyzMaterial(int num = 2, bool needExosister = false)
+ {
+ List materialList = Bot.GetMonsters().Where(card => CheckAbleForXyz(card)).ToList();
+ if (materialList?.Count() < num)
+ {
+ return;
+ }
+ if (needExosister && !materialList.Any(card => card.HasSetcode(SetcodeExosister)))
+ {
+ return;
+ }
+ List selectedList = new List();
+
+ // if needed, select exosister with less atk first
+ if (needExosister)
+ {
+ List exosisterList = materialList.Where(card => card.HasSetcode(SetcodeExosister)).ToList();
+ exosisterList.Sort(CardContainer.CompareCardAttack);
+ ClientCard firstSelect = exosisterList[0];
+ selectedList.Add(firstSelect);
+ materialList.Remove(firstSelect);
+ }
+
+ // select non-exosister or effecte used's exosister first
+ // never use martha first
+ List sortMaterialList = materialList.Where(card =>
+ (card?.Data != null && !card.HasSetcode(SetcodeExosister)) || (exosisterTransformEffectList.Contains(card.Id) && card.Id != CardId.ExosisterMartha)).ToList();
+ sortMaterialList.Sort(CardContainer.CompareCardAttack);
+ foreach (ClientCard card in sortMaterialList)
+ {
+ selectedList.Add(card);
+ if (selectedList.Count() >= num)
+ {
+ AI.SelectMaterials(selectedList);
+ return;
+ }
+ }
+
+ List valuableMaterialList = materialList.Where(card => card.Id == CardId.ExosisterMartha || !exosisterTransformEffectList.Contains(card.Id)).ToList();
+ valuableMaterialList.Sort(CardContainer.CompareCardAttack);
+ foreach (ClientCard card in valuableMaterialList)
+ {
+ selectedList.Add(card);
+ if (selectedList.Count() >= num)
+ {
+ AI.SelectMaterials(selectedList);
+ return;
+ }
+ }
+ }
+
+ public void SelectDetachMaterial(ClientCard activateCard)
+ {
+ // TODO
+ AI.SelectCard(0);
+ }
+
+ ///
+ /// go first
+ ///
+ public override bool OnSelectHand()
+ {
+ return true;
+ }
+
+ ///
+ /// check whether enemy activate important card
+ ///
+ public override void OnChaining(int player, ClientCard card)
+ {
+ if (card == null) return;
+
+ if (player == 1)
+ {
+ if (card.IsCode(_CardId.MaxxC) && CheckCalledbytheGrave(_CardId.MaxxC) == 0)
+ {
+ enemyActivateMaxxC = true;
+ }
+ if (card.IsCode(_CardId.LockBird) && CheckCalledbytheGrave(_CardId.LockBird) == 0)
+ {
+ enemyActivateLockBird = true;
+ }
+ if (card.IsCode(_CardId.InfiniteImpermanence))
+ {
+ for (int i = 0; i < 5; ++i)
+ {
+ if (Enemy.SpellZone[i] == card)
+ {
+ infiniteImpermanenceList.Add(4 - i);
+ break;
+ }
+ }
+ }
+ if (Duel.LastChainLocation == CardLocation.Grave && card.Location == CardLocation.Grave)
+ {
+ Logger.DebugWriteLine("===Exosister: enemy activate effect from GY.");
+ enemyMoveGrave = true;
+ }
+ }
+ base.OnChaining(player, card);
+ }
+
+ public override void OnSelectChain(IList cards)
+ {
+ int player = Duel.LastChainPlayer;
+ ClientCard card = Util.GetLastChainCard();
+ if (player == 1)
+ {
+ if (card != null && card.IsCode(_CardId.CalledByTheGrave))
+ {
+ foreach (ClientCard targetCard in Duel.LastChainTargets)
+ {
+ Logger.DebugWriteLine("===Exosister: " + targetCard?.Name + " is targeted by called by the grave.");
+ calledbytheGraveCount[targetCard.Id] = 2;
+ }
+ }
+ foreach (ClientCard targetCard in Duel.LastChainTargets)
+ {
+ if (targetCard.Location == CardLocation.Grave)
+ {
+ Logger.DebugWriteLine("===Exosister: enemy target cards of GY.");
+ enemyMoveGrave = true;
+ break;
+ }
+ }
+ }
+ base.OnSelectChain(cards);
+ }
+
+ ///
+ /// clear chain information
+ ///
+ public override void OnChainEnd()
+ {
+ enemyMoveGrave = false;
+ paxCallToField = false;
+ potActivate = false;
+ transformDestList.Clear();
+ targetedMagnificaList.Clear();
+ if (activatedMagnificaList.Count() > 0)
+ {
+ for (int idx = activatedMagnificaList.Count() - 1; idx >= 0; --idx)
+ {
+ ClientCard checkTarget = activatedMagnificaList[idx];
+ if (checkTarget == null || checkTarget.IsFacedown() || checkTarget.Location != CardLocation.MonsterZone)
+ {
+ activatedMagnificaList.RemoveAt(idx);
+ }
+ }
+ }
+ if (spSummonThisTurn.Count() > 0)
+ {
+ for (int idx = spSummonThisTurn.Count() - 1; idx >= 0; --idx)
+ {
+ ClientCard checkTarget = spSummonThisTurn[idx];
+ if (checkTarget == null || checkTarget.IsFacedown() || checkTarget.Location != CardLocation.MonsterZone)
+ {
+ spSummonThisTurn.RemoveAt(idx);
+ }
+ }
+ }
+ base.OnChainEnd();
+ }
+
+ public override void OnNewTurn()
+ {
+ enemyActivateMaxxC = false;
+ enemyActivateLockBird = false;
+ infiniteImpermanenceList.Clear();
+ // CalledbytheGrave refresh
+ List key_list = calledbytheGraveCount.Keys.ToList();
+ foreach (int dic in key_list)
+ {
+ if (calledbytheGraveCount[dic] > 1)
+ {
+ calledbytheGraveCount[dic] -= 1;
+ }
+ }
+
+ summoned = false;
+ elisEffect1Activated = false;
+ stellaEffect1Activated = false;
+ irenaEffect1Activated = false;
+ sophiaEffect1Activated = false;
+ marthaEffect1Activated = false;
+ mikailisEffect1Activated = false;
+ mikailisEffect3Activated = false;
+ kaspitellEffect1Activated = false;
+ kaspitellEffect3Activated = false;
+ gibrineEffect1Activated = false;
+ gibrineEffect3Activated = false;
+ asophielEffect1Activated = false;
+ asophielEffect3Activated = false;
+ sakitamaEffect1Activated = false;
+ exosisterTransformEffectList.Clear();
+ oncePerTurnEffectActivatedList.Clear();
+ activatedMagnificaList.Clear();
+ spSummonThisTurn.Clear();
+ }
+
+ ///
+ /// override for exosister's transform
+ ///
+ public override IList OnSelectCard(IList cards, int min, int max, long hint, bool cancelable)
+ {
+ bool beginTransformCheck = false;
+ // transform for main monster
+ if (hint == HintMsg.SpSummon && min == 1 && max == 1 && transformDestList.Count() > 0)
+ {
+ // check whether for transform
+ if (cards.All(card => card.Location == CardLocation.Extra && card.Rank == 4 && card.HasSetcode(SetcodeExosister)))
+ {
+ beginTransformCheck = true;
+ }
+ }
+ // transform for magnifica
+ if (hint == HintMsg.ToDeck && min == 1 && max == 1 && transformDestList.Count() > 0)
+ {
+ if (cards.All(card => card.Location == CardLocation.Overlay))
+ {
+ beginTransformCheck = true;
+ }
+ }
+ if (beginTransformCheck)
+ {
+ for (int idx = 0; idx < transformDestList.Count(); ++idx)
+ {
+ int targetId = transformDestList[idx];
+ ClientCard targetCard = cards.FirstOrDefault(card => card.IsCode(targetId));
+ if (targetCard != null)
+ {
+ List result = new List();
+ result.Add(targetCard);
+ transformDestList.RemoveAt(idx);
+ spSummonThisTurn.AddRange(result);
+ return Util.CheckSelectCount(result, cards, min, max);
+ }
+ }
+ }
+
+ if (Util.ChainContainsCard(_CardId.EvenlyMatched) && Util.ChainContainPlayer(1) && hint == HintMsg.Remove)
+ {
+ int botCount = Bot.GetMonsterCount() + Bot.GetSpellCount();
+ int oppositeCount = Enemy.GetMonsterCount() + Enemy.GetSpellCount();
+ if (botCount - oppositeCount == min && min == max)
+ {
+ Logger.DebugWriteLine("===Exosister: Evenly Matched activated.");
+ List allBotCards = new List();
+ allBotCards.AddRange(Bot.GetMonsters());
+ allBotCards.AddRange(Bot.GetSpells());
+ List importantList = new List();
+
+ List magnificaList = allBotCards.Where(card => card.IsCode(CardId.ExosistersMagnifica)).ToList();
+ if (magnificaList.Count > 0)
+ {
+ allBotCards.RemoveAll(c => magnificaList.Contains(c));
+ importantList.AddRange(magnificaList);
+ }
+ if (!mikailisEffect1Activated)
+ {
+ List mikailisList = allBotCards.Where(card => spSummonThisTurn.Contains(card)
+ && card.IsCode(CardId.ExosisterMikailis) && card.IsFaceup()).ToList();
+ if (mikailisList.Count > 0)
+ {
+ allBotCards.RemoveAll(c => mikailisList.Contains(c));
+ importantList.AddRange(mikailisList);
+ }
+ }
+ if (!gibrineEffect1Activated)
+ {
+ List gibrineList = allBotCards.Where(card => spSummonThisTurn.Contains(card)
+ && card.IsCode(CardId.ExosisterGibrine) && card.IsFaceup()).ToList();
+ if (gibrineList.Count > 0)
+ {
+ allBotCards.RemoveAll(c => gibrineList.Contains(c));
+ importantList.AddRange(gibrineList);
+ }
+ }
+ if (!oncePerTurnEffectActivatedList.Contains(CardId.ExosisterVadis))
+ {
+ List vadisList = allBotCards.Where(card => card.IsCode(CardId.ExosisterVadis) && card.IsFacedown()).ToList();
+ if (vadisList.Count > 0)
+ {
+ allBotCards.RemoveAll(c => vadisList.Contains(c));
+ importantList.AddRange(vadisList);
+ }
+ }
+ List xyzList = allBotCards.Where(card => card.IsMonster() && card.HasType(CardType.Xyz)).ToList();
+ if (xyzList.Count > 0)
+ {
+ xyzList.Sort(CardContainer.CompareCardAttack);
+ xyzList.Reverse();
+ allBotCards.RemoveAll(c => xyzList.Contains(c));
+ importantList.AddRange(xyzList);
+ }
+ List monsterList = allBotCards.Where(card => card.IsMonster()).ToList();
+ if (monsterList.Count > 0)
+ {
+ monsterList.Sort(CardContainer.CompareCardAttack);
+ monsterList.Reverse();
+ allBotCards.RemoveAll(c => monsterList.Contains(c));
+ importantList.AddRange(monsterList);
+ }
+ List faceDownList = allBotCards.Where(card => card.IsFacedown()).ToList();
+ if (faceDownList.Count > 0)
+ {
+ allBotCards.RemoveAll(c => faceDownList.Contains(c));
+ importantList.AddRange(ShuffleCardList(faceDownList));
+ }
+
+ importantList.Reverse();
+ return Util.CheckSelectCount(importantList, cards, min, max);
+ }
+ }
+
+ return base.OnSelectCard(cards, min, max, hint, cancelable);
+ }
+
+ public override CardPosition OnSelectPosition(int cardId, IList positions)
+ {
+ YGOSharp.OCGWrapper.NamedCard cardData = YGOSharp.OCGWrapper.NamedCard.Get(cardId);
+ if (cardData != null)
+ {
+ if (Util.IsTurn1OrMain2())
+ {
+ bool turnDefense = false;
+ if (cardId == CardId.DivineArsenalAAZEUS_SkyThunder || cardId == CardId.ExosistersMagnifica)
+ {
+ turnDefense = true;
+ }
+ if (!cardData.HasType(CardType.Xyz))
+ {
+ turnDefense = true;
+ }
+ if (turnDefense)
+ {
+ return CardPosition.FaceUpDefence;
+ }
+ }
+ if (Duel.Player == 1)
+ {
+ if (!cardData.HasType(CardType.Xyz) || cardData.Defense >= cardData.Attack || Util.IsOneEnemyBetterThanValue(cardData.Attack, true))
+ {
+ return CardPosition.FaceUpDefence;
+ }
+ }
+ int bestBotAttack = Math.Max(Util.GetBestAttack(Bot), cardData.Attack);
+ if (Util.IsAllEnemyBetterThanValue(bestBotAttack, true))
+ {
+ return CardPosition.FaceUpDefence;
+ }
+ }
+ return base.OnSelectPosition(cardId, positions);
+ }
+
+ ///
+ /// override for magnifica's spsummon
+ ///
+ public override bool OnSelectYesNo(int desc)
+ {
+ // magnifica spsummon
+ if (desc == Util.GetStringId(CardId.ExosistersMagnifica, 2))
+ {
+ return true;
+ }
+ // pax spsummon
+ if (desc == Util.GetStringId(CardId.ExosisterPax, 1))
+ {
+ return paxCallToField;
+ }
+
+ return base.OnSelectYesNo(desc);
+ }
+
+ ///
+ /// override for returnia's option
+ ///
+ public override int OnSelectOption(IList options)
+ {
+ // check retunia
+ int spSummonOption = -1;
+ int banishOption = -1;
+ int doNothingOption = -1;
+ for (int idx = 0; idx < options.Count(); ++idx)
+ {
+ int option = options[idx];
+ if (option == Util.GetStringId(CardId.ExosisterReturnia, 0))
+ {
+ spSummonOption = idx;
+ }
+ else if (option == Util.GetStringId(CardId.ExosisterReturnia, 1))
+ {
+ banishOption = idx;
+ }
+ else if (option == Util.GetStringId(CardId.ExosisterReturnia, 2))
+ {
+ doNothingOption = idx;
+ }
+ }
+
+ if (spSummonOption >= 0 || banishOption >= 0 || doNothingOption >= 0)
+ {
+ if (spSummonOption < 0 && banishOption < 0)
+ {
+ return doNothingOption;
+ }
+ if (banishOption >= 0)
+ {
+ // banish problem card
+ ClientCard target = GetProblematicEnemyCard(true);
+ if (target != null)
+ {
+ AI.SelectCard(target);
+ return banishOption;
+ }
+
+ // dump banish
+ target = GetBestEnemyCard(false, false);
+ if (target != null)
+ {
+ AI.SelectCard(target);
+ return banishOption;
+ }
+ }
+ if (spSummonOption >= 0)
+ {
+ // TODO
+ }
+ }
+
+ // check pot
+ int potBanish6Option = -1;
+ int potBanish3Option = -1;
+ for (int idx = 0; idx < options.Count(); ++idx)
+ {
+ int option = options[idx];
+ if (option == Util.GetStringId(CardId.PotofExtravagance, 0))
+ {
+ potBanish3Option = idx;
+ }
+ else if (option == Util.GetStringId(CardId.PotofExtravagance, 1))
+ {
+ potBanish6Option = idx;
+ }
+ }
+ if (potBanish3Option >= 0 || potBanish6Option >= 0)
+ {
+ if (Bot.ExtraDeck.Count() > 9 && potBanish6Option >= 0)
+ {
+ return potBanish6Option;
+ }
+ return potBanish3Option;
+ }
+
+ return base.OnSelectOption(options);
+ }
+
+ public bool AshBlossomActivate()
+ {
+ if (CheckWhetherNegated(true) || !CheckLastChainShouldNegated()) return false;
+ if (Duel.LastChainPlayer == 1 && Util.GetLastChainCard().IsCode(_CardId.MaxxC))
+ {
+ if (CheckAtAdvantage())
+ {
+ return false;
+ }
+ }
+ CheckDeactiveFlag();
+ return DefaultAshBlossomAndJoyousSpring();
+ }
+
+ public bool MaxxCActivate()
+ {
+ if (CheckWhetherNegated(true) || Duel.LastChainPlayer == 0) return false;
+ return DefaultMaxxC();
+ }
+
+ public bool InfiniteImpermanenceActivate()
+ {
+ if (CheckWhetherNegated()) return false;
+ // negate before effect used
+ foreach (ClientCard m in Enemy.GetMonsters())
+ {
+ if (m.IsMonsterShouldBeDisabledBeforeItUseEffect() && !m.IsDisabled() && Duel.LastChainPlayer != 0)
+ {
+ if (Card.Location == CardLocation.SpellZone)
+ {
+ for (int i = 0; i < 5; ++i)
+ {
+ if (Bot.SpellZone[i] == Card)
+ {
+ infiniteImpermanenceList.Add(i);
+ break;
+ }
+ }
+ }
+ if (Card.Location == CardLocation.Hand)
+ {
+ SelectSTPlace(Card, true);
+ }
+ AI.SelectCard(m);
+ return true;
+ }
+ }
+
+ ClientCard LastChainCard = Util.GetLastChainCard();
+
+ // negate spells
+ if (Card.Location == CardLocation.SpellZone)
+ {
+ int this_seq = -1;
+ int that_seq = -1;
+ for (int i = 0; i < 5; ++i)
+ {
+ if (Bot.SpellZone[i] == Card) this_seq = i;
+ if (LastChainCard != null
+ && LastChainCard.Controller == 1 && LastChainCard.Location == CardLocation.SpellZone && Enemy.SpellZone[i] == LastChainCard) that_seq = i;
+ else if (Duel.Player == 0 && Util.GetProblematicEnemySpell() != null
+ && Enemy.SpellZone[i] != null && Enemy.SpellZone[i].IsFloodgate()) that_seq = i;
+ }
+ if ((this_seq * that_seq >= 0 && this_seq + that_seq == 4)
+ || (Util.IsChainTarget(Card))
+ || (LastChainCard != null && LastChainCard.Controller == 1 && LastChainCard.IsCode(_CardId.HarpiesFeatherDuster)))
+ {
+ ClientCard target = GetProblematicEnemyMonster(canBeTarget: true);
+ List enemyMonsters = Enemy.GetMonsters();
+ CheckDeactiveFlag();
+ AI.SelectCard(target);
+ infiniteImpermanenceList.Add(this_seq);
+ return true;
+ }
+ }
+ if ((LastChainCard == null || LastChainCard.Controller != 1 || LastChainCard.Location != CardLocation.MonsterZone
+ || LastChainCard.IsDisabled() || LastChainCard.IsShouldNotBeTarget() || LastChainCard.IsShouldNotBeSpellTrapTarget()))
+ return false;
+ // negate monsters
+ if (Card.Location == CardLocation.SpellZone)
+ {
+ for (int i = 0; i < 5; ++i)
+ {
+ if (Bot.SpellZone[i] == Card)
+ {
+ infiniteImpermanenceList.Add(i);
+ break;
+ }
+ }
+ }
+ if (Card.Location == CardLocation.Hand)
+ {
+ SelectSTPlace(Card, true);
+ }
+ if (LastChainCard != null) AI.SelectCard(LastChainCard);
+ else
+ {
+ List enemyMonsters = Enemy.GetMonsters();
+ enemyMonsters.Sort(CardContainer.CompareCardAttack);
+ enemyMonsters.Reverse();
+ foreach (ClientCard card in enemyMonsters)
+ {
+ if (card.IsFaceup() && !card.IsShouldNotBeTarget() && !card.IsShouldNotBeSpellTrapTarget())
+ {
+ CheckDeactiveFlag();
+ AI.SelectCard(card);
+ return true;
+ }
+ }
+ }
+ return true;
+ }
+
+ public bool CalledbytheGraveActivate()
+ {
+ if (CheckWhetherNegated(true)) return false;
+ if (Duel.LastChainPlayer == 1)
+ {
+ // negate
+ if (Util.GetLastChainCard().IsMonster())
+ {
+ int code = Util.GetLastChainCard().Id;
+ if (code == 0) return false;
+ if (CheckCalledbytheGrave(code) > 0) return false;
+ if (Util.GetLastChainCard().IsCode(_CardId.MaxxC) && CheckAtAdvantage())
+ {
+ return false;
+ }
+ if (code == CardId.DimensionShifter)
+ {
+ return false;
+ }
+ if (Enemy.Graveyard.GetFirstMatchingCard(card => card.IsMonster() && card.IsOriginalCode(code)) != null)
+ {
+ if (!(Card.Location == CardLocation.SpellZone))
+ {
+ SelectSTPlace(null, true);
+ }
+ AI.SelectCard(code);
+ calledbytheGraveCount[code] = 2;
+ CheckDeactiveFlag();
+ return true;
+ }
+ }
+
+ // banish target
+ foreach (ClientCard cards in Enemy.Graveyard)
+ {
+ if (Duel.ChainTargets.Contains(cards))
+ {
+ int code = cards.Id;
+ AI.SelectCard(cards);
+ calledbytheGraveCount[code] = 2;
+ return true;
+ }
+ }
+
+ // become targets
+ if (Duel.ChainTargets.Contains(Card))
+ {
+ List enemyMonsters = Enemy.Graveyard.GetMatchingCards(card => card.IsMonster()).ToList();
+ if (enemyMonsters.Count > 0)
+ {
+ enemyMonsters.Sort(CardContainer.CompareCardAttack);
+ enemyMonsters.Reverse();
+ int code = enemyMonsters[0].Id;
+ AI.SelectCard(code);
+ calledbytheGraveCount[code] = 2;
+ return true;
+ }
+ }
+ }
+
+ // avoid danger monster in grave
+ if (Duel.LastChainPlayer == 1) return false;
+ List targets = CheckDangerousCardinEnemyGrave(true);
+ if (targets.Count() > 0)
+ {
+ int code = targets[0].Id;
+ if (!(Card.Location == CardLocation.SpellZone))
+ {
+ SelectSTPlace(null, true);
+ }
+ AI.SelectCard(code);
+ calledbytheGraveCount[code] = 2;
+ return true;
+ }
+
+ return false;
+ }
+
+ public List GetPotofExtravaganceBanish()
+ {
+ List banishList = new List();
+ ClientCard aaZeus = Bot.ExtraDeck.FirstOrDefault(card => card.IsCode(CardId.DivineArsenalAAZEUS_SkyThunder));
+ if (aaZeus != null)
+ {
+ banishList.Add(aaZeus);
+ }
+
+ ClientCard diamond = Bot.ExtraDeck.FirstOrDefault(card => card.IsCode(CardId.StellarknightConstellarDiamond));
+ if (diamond != null)
+ {
+ banishList.Add(diamond);
+ }
+
+ ClientCard caduceus = Bot.ExtraDeck.FirstOrDefault(card => card.IsCode(CardId.TellarknightConstellarCaduceus));
+ if (caduceus != null)
+ {
+ banishList.Add(caduceus);
+ }
+
+ ClientCard evilswarm = Bot.ExtraDeck.FirstOrDefault(card => card.IsCode(_CardId.EvilswarmExcitonKnight));
+ if (evilswarm != null)
+ {
+ banishList.Add(evilswarm);
+ }
+
+ // second asophiel
+ if (Bot.ExtraDeck.Count(card => card.IsCode(CardId.ExosisterAsophiel)) > 1)
+ {
+ ClientCard asophiel2 = Bot.ExtraDeck.FirstOrDefault(card => card.IsCode(CardId.ExosisterAsophiel));
+ banishList.Add(asophiel2);
+ }
+
+ ClientCard gibrine = Bot.ExtraDeck.FirstOrDefault(card => card.IsCode(CardId.ExosisterGibrine));
+ if (gibrine != null)
+ {
+ banishList.Add(gibrine);
+ }
+
+ // 6 done
+
+ // third mikailis
+ if (Bot.ExtraDeck.Count(card => card.IsCode(CardId.ExosisterMikailis)) > 2)
+ {
+ ClientCard mikailis3 = Bot.ExtraDeck.FirstOrDefault(card => card.IsCode(CardId.ExosisterMikailis));
+ banishList.Add(mikailis3);
+ }
+
+ // first asophiel
+ ClientCard asophiel1 = Bot.ExtraDeck.FirstOrDefault(card => card.IsCode(CardId.ExosisterAsophiel) && !banishList.Contains(card));
+ if (asophiel1 != null)
+ {
+ banishList.Add(asophiel1);
+ }
+
+ ClientCard donner = Bot.ExtraDeck.FirstOrDefault(card => card.IsCode(CardId.DonnerDaggerFurHire));
+ if (donner != null)
+ {
+ banishList.Add(donner);
+ }
+
+ // 9 done
+
+ // second kaspitell
+ if (Bot.ExtraDeck.Count(card => card.IsCode(CardId.ExosisterKaspitell)) > 1)
+ {
+ ClientCard kaspitell = Bot.ExtraDeck.FirstOrDefault(card => card.IsCode(CardId.ExosisterKaspitell));
+ banishList.Add(kaspitell);
+ }
+
+ // second magnifica
+ if (Bot.ExtraDeck.Count(card => card.IsCode(CardId.ExosistersMagnifica)) > 1)
+ {
+ ClientCard magnifica2 = Bot.ExtraDeck.FirstOrDefault(card => card.IsCode(CardId.ExosistersMagnifica));
+ banishList.Add(magnifica2);
+ }
+
+ // second mikailis
+ if (Bot.ExtraDeck.Count(card => card.IsCode(CardId.ExosisterMikailis)) > 1)
+ {
+ ClientCard mikailis2 = Bot.ExtraDeck.FirstOrDefault(card => card.IsCode(CardId.ExosisterMikailis) && !banishList.Contains(card));
+ banishList.Add(mikailis2);
+ }
+
+ // first magnifica
+ ClientCard magnifica1 = Bot.ExtraDeck.FirstOrDefault(card => card.IsCode(CardId.ExosistersMagnifica) && !banishList.Contains(card));
+ if (magnifica1 != null)
+ {
+ banishList.Add(magnifica1);
+ }
+
+ // first kaspitell
+ ClientCard kaspitell1 = Bot.ExtraDeck.FirstOrDefault(card => card.IsCode(CardId.ExosisterKaspitell) && !banishList.Contains(card));
+ if (kaspitell1 != null)
+ {
+ banishList.Add(kaspitell1);
+ }
+
+ // first mikailis1
+ ClientCard mikailis1 = Bot.ExtraDeck.FirstOrDefault(card => card.IsCode(CardId.ExosisterMikailis) && !banishList.Contains(card));
+ if (mikailis1 != null)
+ {
+ banishList.Add(mikailis1);
+ }
+
+ return banishList;
+ }
+
+ public bool PotofExtravaganceActivate()
+ {
+ if (CheckWhetherNegated())
+ {
+ return false;
+ }
+ List banishList = GetPotofExtravaganceBanish();
+
+ List addToHandOrderList = new List();
+
+ bool marthaActivatable = CheckMarthaActivatable();
+ if (marthaActivatable)
+ {
+ if (!Bot.HasInHand(CardId.ExosisterMartha))
+ {
+ addToHandOrderList.Add(CardId.ExosisterMartha);
+ }
+ if (Bot.HasInHand(CardId.ExosisterMartha) && !Bot.HasInHandOrInSpellZone(_CardId.CalledByTheGrave))
+ {
+ addToHandOrderList.Add(_CardId.CalledByTheGrave);
+ }
+ }
+ int exosisterCount = Bot.Hand.Count(card => card?.Data != null && card.HasSetcode(SetcodeExosister));
+ if (!stellaEffect1Activated && CheckCalledbytheGrave(CardId.ExosisterStella) == 0)
+ {
+ if (!Bot.HasInHand(CardId.ExosisterStella) && exosisterCount > 0)
+ {
+ addToHandOrderList.Add(CardId.ExosisterStella);
+ }
+ if (Bot.HasInHand(CardId.ExosisterStella) && exosisterCount == 0)
+ {
+ addToHandOrderList.AddRange(new List{
+ CardId.ExosisterSophia, CardId.ExosisterIrene, CardId.ExosisterStella, CardId.ExosisterMartha, CardId.ExosisterElis});
+ }
+ }
+ if (exosisterCount >= 0 && !Bot.HasInHandOrInSpellZone(CardId.ExosisterReturnia))
+ {
+ addToHandOrderList.Add(CardId.ExosisterReturnia);
+ }
+ List remainOrderList = new List{
+ CardId.Aratama, CardId.Sakitama, _CardId.MaxxC, _CardId.AshBlossom, _CardId.InfiniteImpermanence,
+ _CardId.CalledByTheGrave, CardId.ExosisterVadis, CardId.ExosisterReturnia, CardId.ExosisterPax
+ };
+ addToHandOrderList.AddRange(remainOrderList);
+
+ AI.SelectCard(banishList);
+ AI.SelectNextCard(addToHandOrderList);
+ if (!(Card.Location == CardLocation.SpellZone))
+ {
+ SelectSTPlace(null, true);
+ }
+
+ potActivate = true;
+ return true;
+ }
+
+ public bool SakitamaActivate()
+ {
+ // summon
+ if (Card.Location == CardLocation.Hand)
+ {
+ // summon for xyz
+ if (Bot.GetMonsters().Count(card => CheckAbleForXyz(card)) == 1)
+ {
+ AI.SelectCard(CardId.Aratama, CardId.Sakitama);
+ sakitamaEffect1Activated = true;
+ return true;
+ }
+
+ // summon for summon donner
+ if (!CheckLessOperation() && Bot.HasInExtra(CardId.DonnerDaggerFurHire) &&
+ !Bot.HasInHand(CardId.ExosisterMartha) || Bot.HasInHandOrInSpellZone(CardId.ExosisterReturnia))
+ {
+ List illegalList = Bot.GetMonsters().Where(card => card.IsFaceup() && !card.HasType(CardType.Xyz) && card.Level != 4
+ && (card.Data == null || !card.HasSetcode(SetcodeExosister))).ToList();
+ if (illegalList.Count() > 0)
+ {
+ if (illegalList.Count() == 1)
+ {
+ List otherMaterialList = Bot.GetMonsters().Where(card => card.IsFaceup() && !card.HasType(CardType.Xyz)).ToList();
+ otherMaterialList.Sort(CardContainer.CompareCardAttack);
+ illegalList.AddRange(otherMaterialList);
+ }
+ if (illegalList.Count() == 1)
+ {
+ Logger.DebugWriteLine("===Exosister: activate sakitama for donner");
+ AI.SelectCard(CardId.Aratama, CardId.Sakitama);
+ sakitamaEffect1Activated = true;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ // add to hand
+ if (Card.Location == CardLocation.Grave)
+ {
+ AI.SelectCard(CardId.Sakitama, CardId.Aratama);
+ return true;
+ }
+ return true;
+ }
+
+ public bool DonnerDaggerFurHireActivate()
+ {
+ if (CheckAtAdvantage() && !Bot.HasInHand(CardId.ExosisterMartha) && !Bot.HasInHandOrInSpellZone(CardId.ExosisterReturnia))
+ {
+ return false;
+ }
+
+ ClientCard targetCard = Util.GetProblematicEnemyMonster(canBeTarget: true);
+ if (targetCard == null)
+ {
+ List enemyMonsters = Enemy.GetMonsters();
+ if (enemyMonsters.Count() > 0)
+ {
+ enemyMonsters.Sort(CardContainer.CompareCardAttack);
+ enemyMonsters.Reverse();
+ targetCard = enemyMonsters[0];
+ }
+ }
+
+ if (targetCard != null)
+ {
+ AI.SelectCard(Card);
+ AI.SelectNextCard(targetCard);
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool ExosisterElisActivate()
+ {
+ if (ActivateDescription != Util.GetStringId(CardId.ExosisterElis, 0))
+ {
+ return false;
+ }
+
+ if (Bot.GetMonsters().Count(card => CheckAbleForXyz(card)) == 1)
+ {
+ elisEffect1Activated = true;
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool ExosisterStellaActivate()
+ {
+ return ExosisterStellaActivateInner(true);
+ }
+
+ public bool ExosisterStellaSecondActivate()
+ {
+ return ExosisterStellaActivateInner(false);
+ }
+
+ public bool ExosisterStellaActivateInner(bool checkMartha = false)
+ {
+ if (ActivateDescription != Util.GetStringId(CardId.ExosisterStella, 0) || CheckWhetherNegated(true))
+ {
+ return false;
+ }
+
+ bool ableToXyz = Bot.GetMonsters().Count(card => CheckAbleForXyz(card)) >= 2;
+
+ if (CheckLessOperation() && ableToXyz)
+ {
+ return false;
+ }
+ if (checkMartha && Bot.HasInHand(CardId.ExosisterMartha) && ableToXyz
+ && Bot.Hand.Count(card => card.IsMonster() && card.HasSetcode(CardId.ExosisterMartha)) == 1)
+ {
+ return false;
+ }
+
+ AI.SelectCard(CardId.ExosisterSophia, CardId.ExosisterIrene, CardId.ExosisterStella, CardId.ExosisterElis);
+ stellaEffect1Activated = true;
+ return true;
+ }
+
+ public bool ExosisterIreneActivate()
+ {
+ if (ActivateDescription != Util.GetStringId(CardId.ExosisterIrene, 0) || CheckWhetherNegated(true))
+ {
+ return false;
+ }
+
+ List shuffleList = new List();
+ foreach (int cardId in new List { CardId.ExosisterIrene, CardId.ExosisterSophia, CardId.ExosisterArment })
+ {
+ if (Bot.HasInHand(cardId))
+ {
+ shuffleList.Add(cardId);
+ }
+ }
+ if (elisEffect1Activated || Bot.Hand.Count(card => card.IsCode(CardId.ExosisterElis)) > 1)
+ {
+ shuffleList.Add(CardId.ExosisterElis);
+ }
+ foreach (int cardId in new List { CardId.ExosisterPax, CardId.ExosisterReturnia, CardId.ExosisterVadis })
+ {
+ if ((oncePerTurnEffectActivatedList.Contains(cardId) && Bot.HasInHand(cardId)) || Bot.Hand.Count(card => card.IsCode(cardId)) > 1)
+ {
+ shuffleList.Add(cardId);
+ }
+ }
+
+ if (shuffleList.Count() > 0)
+ {
+ Logger.DebugWriteLine("===Exosister: irene return " + shuffleList[0]);
+ AI.SelectCard(shuffleList);
+ return true;
+ }
+ return false;
+ }
+
+ public bool ExosisterSophiaActivate()
+ {
+ if (ActivateDescription == Util.GetStringId(CardId.ExosisterSophia, 0) && !CheckWhetherNegated(true))
+ {
+ sophiaEffect1Activated = true;
+ return true;
+ }
+ return false;
+ }
+
+ public bool ExosisterMarthaActivate()
+ {
+ if (ActivateDescription != Util.GetStringId(CardId.ExosisterMartha, 0))
+ {
+ return false;
+ }
+ if (CheckLessOperation() && Bot.GetMonsterCount() > 0)
+ {
+ return false;
+ }
+
+ marthaEffect1Activated = true;
+ return true;
+ }
+
+ public bool DefaultExosisterTransform()
+ {
+ List canTransformList = new List
+ {
+ CardId.ExosisterElis, CardId.ExosisterStella, CardId.ExosisterIrene, CardId.ExosisterSophia, CardId.ExosisterMartha
+ };
+ if (Card.IsDisabled() || !canTransformList.Contains(Card.Id))
+ {
+ return false;
+ }
+ List checkTransformCode = new List{
+ Util.GetStringId(CardId.ExosisterElis, 1),
+ Util.GetStringId(CardId.ExosisterStella, 1),
+ Util.GetStringId(CardId.ExosisterIrene, 1),
+ Util.GetStringId(CardId.ExosisterSophia, 1),
+ Util.GetStringId(CardId.ExosisterMartha, 1)
+ };
+ if (!checkTransformCode.Contains(ActivateDescription) && ActivateDescription != -1)
+ {
+ return false;
+ }
+
+ // mikailis
+ if (!Bot.HasInMonstersZone(CardId.ExosisterMikailis) && !mikailisEffect1Activated && (Duel.Player == 1 || !mikailisEffect3Activated)
+ && !transformDestList.Contains(CardId.ExosisterMikailis) && Bot.HasInExtra(CardId.ExosisterMikailis))
+ {
+ exosisterTransformEffectList.Add(Card.Id);
+ transformDestList.Add(CardId.ExosisterMikailis);
+ return true;
+ }
+
+ // kaspitell on bot's turn
+ if (!Bot.HasInMonstersZone(CardId.ExosisterKaspitell) && !kaspitellEffect3Activated && Duel.Player == 0
+ && !transformDestList.Contains(CardId.ExosisterKaspitell) && Bot.HasInExtra(CardId.ExosisterKaspitell))
+ {
+ exosisterTransformEffectList.Add(Card.Id);
+ transformDestList.Add(CardId.ExosisterKaspitell);
+ return true;
+ }
+
+ // gibrine
+ if (!Bot.HasInMonstersZone(CardId.ExosisterGibrine) && !gibrineEffect1Activated
+ && !transformDestList.Contains(CardId.ExosisterGibrine) && Bot.HasInExtra(CardId.ExosisterGibrine))
+ {
+ exosisterTransformEffectList.Add(Card.Id);
+ transformDestList.Add(CardId.ExosisterGibrine);
+ return true;
+ }
+
+ // asophiel
+ if (!Bot.HasInMonstersZone(CardId.ExosisterAsophiel) && !asophielEffect1Activated
+ && !transformDestList.Contains(CardId.ExosisterAsophiel) && Bot.HasInExtra(CardId.ExosisterAsophiel))
+ {
+ exosisterTransformEffectList.Add(Card.Id);
+ transformDestList.Add(CardId.ExosisterAsophiel);
+ return true;
+ }
+
+ // kaspitell on bot's turn
+ if (!Bot.HasInMonstersZone(CardId.ExosisterKaspitell) && !kaspitellEffect1Activated
+ && !transformDestList.Contains(CardId.ExosisterKaspitell) && Bot.HasInExtra(CardId.ExosisterKaspitell))
+ {
+ exosisterTransformEffectList.Add(Card.Id);
+ transformDestList.Add(CardId.ExosisterKaspitell);
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool ExosisterMikailisActivate()
+ {
+ // banish
+ if (ActivateDescription == Util.GetStringId(CardId.ExosisterMikailis, 0))
+ {
+ // activate after search
+ if (Duel.Player == 0 && !mikailisEffect3Activated && Duel.Phase < DuelPhase.End && !DefaultOnBecomeTarget())
+ {
+ return false;
+ }
+
+ // banish problem card
+ ClientCard target = GetProblematicEnemyCard(true);
+ if (target != null && Duel.LastChainPlayer != 0)
+ {
+ removeChosenList.Add(target);
+ mikailisEffect1Activated = true;
+ AI.SelectCard(target);
+ return true;
+ }
+
+ // banish target
+ if (Duel.LastChainPlayer == 1)
+ {
+ List targetList = Duel.LastChainTargets.Where(card => card.Controller == 1 &&
+ (card.Location == CardLocation.Grave || card.Location == CardLocation.MonsterZone || card.Location == CardLocation.SpellZone || card.Location == CardLocation.FieldZone)).ToList();
+ if (targetList.Count() > 0)
+ {
+ mikailisEffect1Activated = true;
+ AI.SelectCard(ShuffleCardList(targetList));
+ return true;
+ }
+ }
+
+ // dump banish
+ target = GetBestEnemyCard(false, true, true);
+ if ((DefaultOnBecomeTarget() && !Util.ChainContainsCard(_CardId.EvenlyMatched)) || Bot.UnderAttack || (Duel.Phase == DuelPhase.End && Duel.LastChainPlayer != 0)
+ || (Duel.Player == 0 && Bot.GetMonsters().Count(card => card.HasType(CardType.Xyz) && card.Rank == 4 && card.HasSetcode(SetcodeExosister)) == 2 && Duel.LastChainPlayer != 0)
+ || (Duel.Player == 1 && Enemy.GetMonsterCount() >= 2))
+ {
+ mikailisEffect1Activated = true;
+ AI.SelectCard(target);
+ return true;
+ }
+ return false;
+ }
+
+ // search
+ if (CheckWhetherNegated(true))
+ {
+ return false;
+ }
+
+ List searchTarget = new List{
+ CardId.ExosisterReturnia,
+ CardId.ExosisterVadis,
+ CardId.ExosisterPax,
+ CardId.ExosisterArment
+ };
+ List firstSearchList = new List();
+ List lastSearchList = new List();
+ foreach (int cardId in searchTarget)
+ {
+ if (Bot.HasInHandOrInSpellZone(cardId) || CheckRemainInDeck(cardId) == 0)
+ {
+ lastSearchList.Add(cardId);
+ continue;
+ }
+ if (cardId == CardId.ExosisterReturnia && Bot.GetMonsters().Any(card => card.IsFacedown() || !card.HasSetcode(SetcodeExosister)))
+ {
+ lastSearchList.Add(cardId);
+ continue;
+ }
+ firstSearchList.Add(cardId);
+ }
+ firstSearchList.AddRange(lastSearchList);
+
+ mikailisEffect3Activated = true;
+ SelectDetachMaterial(Card);
+ AI.SelectNextCard(firstSearchList);
+ return true;
+ }
+
+ public bool ExosisterKaspitellActivate()
+ {
+ // block spsummon from GY
+ if (ActivateDescription == Util.GetStringId(CardId.ExosisterKaspitell, 0) || ActivateDescription == -1)
+ {
+ if (Enemy.HasInMonstersZone(CardId.InspectorBoarder, true))
+ {
+ return false;
+ }
+ kaspitellEffect1Activated = true;
+ return true;
+ }
+
+ // search
+ if (CheckWhetherNegated(true))
+ {
+ return false;
+ }
+
+ // search martha for activate
+ if (CheckMarthaActivatable() && CheckRemainInDeck(CardId.ExosisterMartha) > 0 && !Bot.HasInHand(CardId.ExosisterMartha))
+ {
+ kaspitellEffect3Activated = true;
+ SelectDetachMaterial(Card);
+ AI.SelectNextCard(CardId.ExosisterMartha);
+ return true;
+ }
+ // search sophia for draw
+ if (!summoned && !sophiaEffect1Activated && CheckCalledbytheGrave(CardId.ExosisterSophia) == 0 && !Bot.HasInHand(CardId.ExosisterSophia)
+ && (Bot.GetMonsters().Count(card => CheckAbleForXyz(card)) == 1 || (Bot.HasInHand(CardId.ExosisterElis) && !elisEffect1Activated)))
+ {
+ kaspitellEffect3Activated = true;
+ SelectDetachMaterial(Card);
+ AI.SelectNextCard(CardId.ExosisterSophia);
+ return true;
+ }
+ // search stella for next xyz
+ if (!summoned && !Bot.HasInHand(CardId.ExosisterStella) && !stellaEffect1Activated && CheckCalledbytheGrave(CardId.ExosisterStella) == 0
+ && CheckRemainInDeck(CardId.ExosisterStella) > 0 && Bot.Hand.Any(card => card?.Data != null && card.IsMonster() && card.HasSetcode(SetcodeExosister)))
+ {
+ kaspitellEffect3Activated = true;
+ SelectDetachMaterial(Card);
+ AI.SelectNextCard(CardId.ExosisterStella);
+ return true;
+ }
+ kaspitellEffect3Activated = true;
+ SelectDetachMaterial(Card);
+ AI.SelectNextCard(CardId.ExosisterMartha, CardId.ExosisterStella, CardId.ExosisterElis, CardId.ExosisterSophia, CardId.ExosisterIrene);
+ return true;
+ }
+
+ public bool ExosisterGibrineActivate()
+ {
+ // negate
+ if (ActivateDescription == Util.GetStringId(CardId.ExosisterGibrine, 0))
+ {
+ if (Duel.Player == 1)
+ {
+ ClientCard target = Enemy.MonsterZone.GetShouldBeDisabledBeforeItUseEffectMonster();
+ if (target != null)
+ {
+ gibrineEffect1Activated = true;
+ AI.SelectCard(target);
+ return true;
+ }
+ }
+
+ ClientCard LastChainCard = Util.GetLastChainCard();
+ if (LastChainCard != null && LastChainCard.Controller == 1 && LastChainCard.Location == CardLocation.MonsterZone &&
+ !LastChainCard.IsDisabled() && !LastChainCard.IsShouldNotBeTarget() && !LastChainCard.IsShouldNotBeMonsterTarget())
+ {
+ gibrineEffect1Activated = true;
+ AI.SelectCard(LastChainCard);
+ return true;
+ }
+
+ return false;
+ }
+
+ // gain atk
+ if (CheckWhetherNegated(true))
+ {
+ return false;
+ }
+ gibrineEffect3Activated = true;
+ SelectDetachMaterial(Card);
+ return true;
+ }
+
+ public bool ExosisterAsophielActivate()
+ {
+ // block activate from GY
+ if (ActivateDescription == Util.GetStringId(CardId.ExosisterAsophiel, 0) || ActivateDescription == -1)
+ {
+ if (Enemy.HasInMonstersZone(CardId.InspectorBoarder, true))
+ {
+ return false;
+ }
+ asophielEffect1Activated = true;
+ return true;
+ }
+
+ // return hand
+ if (CheckWhetherNegated(true))
+ {
+ return false;
+ }
+ ClientCard targetCard = Util.GetProblematicEnemyMonster(0, true);
+ if (targetCard != null)
+ {
+ asophielEffect3Activated = true;
+ SelectDetachMaterial(Card);
+ AI.SelectNextCard(targetCard);
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool ExosistersMagnificaActivateTrigger()
+ {
+ // sp summon
+ if (ActivateDescription == Util.GetStringId(CardId.ExosistersMagnifica, 1))
+ {
+ // return after effect used
+ if (activatedMagnificaList.Contains(Card))
+ {
+ // return to Mikailis for danger card
+ if (Card.Overlays.Contains(CardId.ExosisterMikailis) && !mikailisEffect1Activated)
+ {
+ ClientCard target = GetProblematicEnemyCard(true);
+ if (target != null && !Duel.CurrentChain.Any(card => card == Card))
+ {
+ transformDestList.Add(CardId.ExosisterMikailis);
+ return true;
+ }
+ }
+
+ // negate important card
+ if (Card.Overlays.Contains(CardId.ExosisterGibrine) && !gibrineEffect1Activated)
+ {
+ ClientCard target = Enemy.MonsterZone.GetShouldBeDisabledBeforeItUseEffectMonster();
+ if (target != null)
+ {
+ transformDestList.Add(CardId.ExosisterGibrine);
+ return true;
+ }
+ }
+ }
+
+ // become target
+ if ((DefaultOnBecomeTarget() && !Util.ChainContainsCard(_CardId.EvenlyMatched)) || (Duel.CurrentChain.Any(c => c == Card) && Duel.LastChainPlayer != 0))
+ {
+ targetedMagnificaList.Add(Card);
+ transformDestList.AddRange(new List { CardId.ExosistersMagnifica, CardId.ExosisterMikailis, CardId.ExosisterGibrine, CardId.ExosisterKaspitell, CardId.ExosisterAsophiel });
+ return true;
+ }
+ }
+ return false;
+ }
+ public bool ExosistersMagnificaActivateBanish()
+ {
+ // banish
+ if (ActivateDescription == Util.GetStringId(CardId.ExosistersMagnifica, 0))
+ {
+ if (CheckWhetherNegated())
+ {
+ return false;
+ }
+ // banish problem card
+ ClientCard target = GetProblematicEnemyCard();
+ bool isProblemCard = false;
+ if (target != null)
+ {
+ isProblemCard = true;
+ Logger.DebugWriteLine("===Exosister: magnifica target 1: " + target?.Name);
+ }
+
+ // banish target
+ if (Duel.LastChainPlayer == 1 && target == null)
+ {
+ List currentTargetList = Duel.LastChainTargets.Where(card => card.Controller == 1 &&
+ (card.Location == CardLocation.MonsterZone || card.Location == CardLocation.SpellZone || card.Location == CardLocation.FieldZone)).ToList();
+ if (currentTargetList.Count() > 0)
+ {
+ target = ShuffleCardList(currentTargetList)[0];
+ Logger.DebugWriteLine("===Exosister: magnifica target 2: " + target?.Name);
+ }
+ }
+
+ // dump banish
+ if (target == null)
+ {
+ target = GetBestEnemyCard(false, false);
+ bool check1 = !DefaultOnBecomeTarget() || Util.ChainContainsCard(_CardId.EvenlyMatched);
+ bool check2 = !targetedMagnificaList.Contains(Card);
+ bool check3 = !Bot.UnderAttack;
+ bool check4 = Duel.Phase != DuelPhase.End;
+ bool check5 = Duel.Player == 0 || Enemy.GetMonsterCount() < 2;
+ Logger.DebugWriteLine("===Exosister: magnifica check flag: " + check1 + " " + check2 + " " + check3 + " " + check4 + " " + check5);
+ if (check1 && check2 && check3 && check4 && check5)
+ {
+ target = null;
+ }
+ }
+
+ if (target != null && (Duel.LastChainPlayer != 0 || Util.GetLastChainCard() == Card))
+ {
+ if (isProblemCard)
+ {
+ removeChosenList.Add(target);
+ }
+ Logger.DebugWriteLine("===Exosister: magnifica target final: " + target?.Name);
+ activatedMagnificaList.Add(Card);
+ AI.SelectCard(CardId.ExosisterGibrine, CardId.ExosisterAsophiel, CardId.ExosisterKaspitell, CardId.ExosisterMikailis);
+ AI.SelectNextCard(target);
+ return true;
+ }
+
+ return false;
+ }
+ return false;
+ }
+
+ public bool ExosisterPaxActivate()
+ {
+ if (potActivate || Bot.LifePoints <= 800)
+ {
+ return false;
+ }
+
+ List checkListForSpSummon = new List{
+ CardId.ExosisterSophia, CardId.ExosisterIrene, CardId.ExosisterStella, CardId.ExosisterMartha, CardId.ExosisterElis
+ };
+ List checkListForSearch = new List{
+ CardId.ExosisterMartha, CardId.ExosisterStella, CardId.ExosisterVadis, CardId.ExosisterReturnia, CardId.ExosisterSophia,
+ CardId.ExosisterIrene, CardId.ExosisterArment, CardId.ExosisterElis
+ };
+ if (Duel.Player == 0 && Duel.LastChainPlayer != 0)
+ {
+ // search returnia for banish
+ if (CheckAtAdvantage() && GetProblematicEnemyCard(true) != null && CheckRemainInDeck(CardId.ExosisterReturnia) > 0 && !Bot.HasInHandOrInSpellZone(CardId.ExosisterReturnia))
+ {
+ if (Bot.GetMonsterCount() > 0 && Bot.GetMonsters().All(card => card.IsFaceup() && card.HasSetcode(SetcodeExosister)))
+ {
+ if (!(Card.Location == CardLocation.SpellZone))
+ {
+ SelectSTPlace(null, true);
+ }
+ oncePerTurnEffectActivatedList.Add(Card.Id);
+ AI.SelectCard(CardId.ExosisterReturnia);
+ paxCallToField = false;
+ return true;
+ }
+ }
+
+ // search martha for activate
+ if (CheckMarthaActivatable() && CheckRemainInDeck(CardId.ExosisterMartha) > 0 && !Bot.HasInHand(CardId.ExosisterMartha))
+ {
+ if (!(Card.Location == CardLocation.SpellZone))
+ {
+ SelectSTPlace(null, true);
+ }
+ oncePerTurnEffectActivatedList.Add(Card.Id);
+ AI.SelectCard(CardId.ExosisterMartha);
+ paxCallToField = false;
+ return true;
+ }
+
+ // stella relative
+ if (!stellaEffect1Activated && CheckCalledbytheGrave(CardId.ExosisterStella) == 0)
+ {
+ // try to search stella
+ if (Bot.Hand.Count(card => card.IsCode(CardId.ExosisterStella)) == 0 && CheckRemainInDeck(CardId.ExosisterStella) > 0)
+ {
+ bool shouldSpSummon = !CheckLessOperation() && summoned && Bot.HasInMonstersZoneOrInGraveyard(CardId.ExosisterElis);
+ if (Bot.Hand.Any(card => card?.Data != null && card.IsMonster() && card.HasSetcode(SetcodeExosister)))
+ {
+ if (!(Card.Location == CardLocation.SpellZone))
+ {
+ SelectSTPlace(null, true);
+ }
+ oncePerTurnEffectActivatedList.Add(Card.Id);
+ AI.SelectCard(CardId.ExosisterStella);
+ paxCallToField = shouldSpSummon;
+ return true;
+ }
+ }
+
+ // search monster for stella to summon
+ bool searchExosisterMonster = false;
+ if (Bot.HasInHand(CardId.ExosisterStella) && Bot.Hand.Count(card => card?.Data != null && card.IsMonster() && card.HasSetcode(SetcodeExosister)) == 1)
+ {
+ searchExosisterMonster = true;
+ }
+ if (Bot.HasInMonstersZone(CardId.ExosisterStella) && Bot.Hand.Count(card => card?.Data != null && card.IsMonster() && card.HasSetcode(SetcodeExosister)) == 0)
+ {
+ searchExosisterMonster = true;
+ }
+ if (searchExosisterMonster)
+ {
+ if (!(Card.Location == CardLocation.SpellZone))
+ {
+ SelectSTPlace(null, true);
+ }
+ oncePerTurnEffectActivatedList.Add(Card.Id);
+ AI.SelectCard(CardId.ExosisterSophia, CardId.ExosisterIrene, CardId.ExosisterMartha, CardId.ExosisterStella, CardId.ExosisterElis);
+ paxCallToField = false;
+ return true;
+ }
+ }
+
+ // addition summon
+ if (Bot.GetMonsters().Count(card => CheckAbleForXyz(card)) == 1 && summoned && !CheckLessOperation())
+ {
+ if ((sakitamaEffect1Activated || !Bot.HasInHand(CardId.Sakitama))
+ && (stellaEffect1Activated || !Bot.HasInMonstersZone(CardId.ExosisterStella))
+ && (elisEffect1Activated || !Bot.HasInHand(CardId.ExosisterElis))
+ )
+ {
+ foreach (int checkId in checkListForSpSummon)
+ {
+ int checkTarget = CheckExosisterMentionCard(checkId);
+ if (checkTarget > 0 && Bot.HasInMonstersZoneOrInGraveyard(checkId) && CheckRemainInDeck(checkTarget) > 0)
+ {
+ if (!(Card.Location == CardLocation.SpellZone))
+ {
+ SelectSTPlace(null, true);
+ }
+ oncePerTurnEffectActivatedList.Add(Card.Id);
+ AI.SelectCard(checkId);
+ paxCallToField = true;
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ // in danger
+ bool inDanger = CheckInDanger();
+
+ // trigger transform
+ CheckEnemyMoveGrave();
+
+ bool forReturnia = false;
+ if (!oncePerTurnEffectActivatedList.Contains(CardId.ExosisterReturnia) && Bot.HasInSpellZone(CardId.ExosisterReturnia) && Bot.GetMonsters().Count() == 0)
+ {
+ forReturnia = true;
+ }
+
+ // become target
+ if (enemyMoveGrave || DefaultOnBecomeTarget() || inDanger || forReturnia)
+ {
+ List checkList = checkListForSpSummon;
+ bool shouldSpSummon = enemyMoveGrave || inDanger || forReturnia;
+ if (!shouldSpSummon && !Bot.HasInMonstersZone(new List{
+ CardId.ExosisterElis, CardId.ExosisterStella, CardId.ExosisterIrene, CardId.ExosisterSophia, CardId.ExosisterMartha}))
+ {
+ shouldSpSummon = true;
+ }
+ if (CheckAtAdvantage() && !enemyMoveGrave)
+ {
+ shouldSpSummon = false;
+ checkList = checkListForSearch;
+ }
+ foreach (int checkId in checkList)
+ {
+ bool checkSuccessFlag = false;
+
+ if (shouldSpSummon)
+ {
+ int checkTarget = CheckExosisterMentionCard(checkId);
+ checkSuccessFlag = checkTarget > 0 && Bot.HasInMonstersZoneOrInGraveyard(checkTarget) && CheckRemainInDeck(checkId) > 0
+ && !exosisterTransformEffectList.Contains(checkId) && !Bot.HasInMonstersZone(checkId);
+ }
+ else
+ {
+ checkSuccessFlag = !Bot.HasInHandOrHasInMonstersZone(checkId) && !Bot.HasInSpellZone(checkId) && CheckRemainInDeck(checkId) > 0;
+ }
+
+ if (checkSuccessFlag)
+ {
+ if (!(Card.Location == CardLocation.SpellZone))
+ {
+ SelectSTPlace(null, true);
+ }
+ oncePerTurnEffectActivatedList.Add(Card.Id);
+ AI.SelectCard(checkId);
+ paxCallToField = shouldSpSummon;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public bool ExosisterPaxActivateForEndSearch()
+ {
+ if (potActivate || Bot.LifePoints <= 800)
+ {
+ return false;
+ }
+
+ if (Duel.Player == 0 || Duel.Phase >= DuelPhase.End)
+ {
+ // search spell/trap
+ List checkSpellTrapListForSearch = new List{
+ CardId.ExosisterVadis, CardId.ExosisterMartha, CardId.ExosisterReturnia, CardId.ExosisterStella, CardId.ExosisterSophia,
+ CardId.ExosisterIrene, CardId.ExosisterArment, CardId.ExosisterElis
+ };
+ foreach (int checkId in checkSpellTrapListForSearch)
+ {
+ if (!Bot.HasInHandOrHasInMonstersZone(checkId) && !Bot.HasInSpellZone(checkId) && CheckRemainInDeck(checkId) > 0)
+ {
+ if (!(Card.Location == CardLocation.SpellZone))
+ {
+ SelectSTPlace(null, true);
+ }
+ oncePerTurnEffectActivatedList.Add(Card.Id);
+ AI.SelectCard(CardId.ExosisterSophia, CardId.ExosisterIrene, CardId.ExosisterMartha, CardId.ExosisterStella, CardId.ExosisterElis);
+ paxCallToField = false;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public bool ExosisterArmentActivate()
+ {
+ if (Bot.LifePoints <= 800)
+ {
+ return false;
+ }
+ ClientCard activateTarget = null;
+
+ if (Duel.Player == 0)
+ {
+ bool decided = false;
+
+ // addition summon
+ if (Bot.GetMonsters().Count(card => CheckAbleForXyz(card)) == 1 && summoned && !CheckLessOperation())
+ {
+ if ((sakitamaEffect1Activated || !Bot.HasInHand(CardId.Sakitama))
+ && (stellaEffect1Activated || !Bot.HasInMonstersZone(CardId.ExosisterStella))
+ && (elisEffect1Activated || !Bot.HasInHand(CardId.ExosisterElis))
+ )
+ {
+ decided = true;
+ }
+ }
+
+ if (Duel.LastChainPlayer == 1)
+ {
+ foreach (ClientCard target in Duel.LastChainTargets)
+ {
+ if (target.Controller == 0 && target.Location == CardLocation.MonsterZone && target.IsFaceup() && target.HasSetcode(SetcodeExosister))
+ {
+ activateTarget = target;
+ decided = true;
+ break;
+ }
+ }
+ }
+
+ if (!decided)
+ {
+ return false;
+ }
+ }
+
+ if (activateTarget == null && Duel.LastChainPlayer == 1)
+ {
+ {
+ foreach (ClientCard target in Duel.LastChainTargets)
+ {
+ if (target.Controller == 0 && target.Location == CardLocation.MonsterZone && target.IsFaceup() && target.HasSetcode(SetcodeExosister))
+ {
+ activateTarget = target;
+ break;
+ }
+ }
+ }
+ }
+
+ if (activateTarget == null)
+ {
+ List targetList = Bot.GetMonsters().Where(card => card.IsFaceup() && card.HasSetcode(SetcodeExosister) && !card.HasType(CardType.Xyz)).ToList();
+ if (targetList.Count() > 0)
+ {
+ targetList.Sort(CardContainer.CompareCardAttack);
+ activateTarget = targetList[0];
+ }
+ }
+
+ if (activateTarget == null)
+ {
+ return false;
+ }
+
+ // mikailis
+ if (!Bot.HasInMonstersZone(CardId.ExosisterMikailis) && !mikailisEffect1Activated && (Duel.Player == 1 || !mikailisEffect3Activated)
+ && !transformDestList.Contains(CardId.ExosisterMikailis) && Bot.HasInExtra(CardId.ExosisterMikailis))
+ {
+ if (!(Card.Location == CardLocation.SpellZone))
+ {
+ SelectSTPlace(null, true);
+ }
+ AI.SelectCard(activateTarget);
+ transformDestList.Add(CardId.ExosisterMikailis);
+ return true;
+ }
+
+ // kaspitell on bot's turn
+ if (!Bot.HasInMonstersZone(CardId.ExosisterKaspitell) && !kaspitellEffect3Activated && Duel.Player == 0
+ && !transformDestList.Contains(CardId.ExosisterKaspitell) && Bot.HasInExtra(CardId.ExosisterKaspitell))
+ {
+ if (!(Card.Location == CardLocation.SpellZone))
+ {
+ SelectSTPlace(null, true);
+ }
+ AI.SelectCard(activateTarget);
+ transformDestList.Add(CardId.ExosisterKaspitell);
+ return true;
+ }
+
+ // gibrine
+ if (!Bot.HasInMonstersZone(CardId.ExosisterGibrine) && !gibrineEffect1Activated
+ && !transformDestList.Contains(CardId.ExosisterGibrine) && Bot.HasInExtra(CardId.ExosisterGibrine))
+ {
+ if (!(Card.Location == CardLocation.SpellZone))
+ {
+ SelectSTPlace(null, true);
+ }
+ AI.SelectCard(activateTarget);
+ transformDestList.Add(CardId.ExosisterGibrine);
+ return true;
+ }
+
+ // asophiel
+ if (!Bot.HasInMonstersZone(CardId.ExosisterAsophiel) && !asophielEffect1Activated
+ && !transformDestList.Contains(CardId.ExosisterAsophiel) && Bot.HasInExtra(CardId.ExosisterAsophiel))
+ {
+ if (!(Card.Location == CardLocation.SpellZone))
+ {
+ SelectSTPlace(null, true);
+ }
+ AI.SelectCard(activateTarget);
+ transformDestList.Add(CardId.ExosisterAsophiel);
+ return true;
+ }
+
+ // kaspitell on bot's turn
+ if (!Bot.HasInMonstersZone(CardId.ExosisterKaspitell) && !kaspitellEffect1Activated
+ && !transformDestList.Contains(CardId.ExosisterKaspitell) && Bot.HasInExtra(CardId.ExosisterKaspitell))
+ {
+ if (!(Card.Location == CardLocation.SpellZone))
+ {
+ SelectSTPlace(null, true);
+ }
+ AI.SelectCard(activateTarget);
+ transformDestList.Add(CardId.ExosisterKaspitell);
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool ExosisterVadisActivate()
+ {
+ if (Bot.LifePoints <= 800)
+ {
+ return false;
+ }
+
+ List checkListForSpSummon = new List{
+ CardId.ExosisterSophia, CardId.ExosisterIrene, CardId.ExosisterStella, CardId.ExosisterMartha, CardId.ExosisterElis
+ };
+
+ bool decideToActivate = false;
+ bool checkTransform = false;
+
+ // special summon for xyz
+ if (Duel.Player == 0 && Duel.Phase > DuelPhase.Draw && !CheckLessOperation())
+ {
+ decideToActivate = true;
+ }
+
+ // move grave
+ CheckEnemyMoveGrave();
+ if (enemyMoveGrave)
+ {
+ decideToActivate = true;
+ checkTransform = true;
+ }
+
+ // for returia
+ if (!oncePerTurnEffectActivatedList.Contains(CardId.ExosisterReturnia) && Bot.HasInSpellZone(CardId.ExosisterReturnia) && Bot.GetMonsters().Count() == 0)
+ {
+ decideToActivate = true;
+ }
+
+ if (CheckInDanger() || (DefaultOnBecomeTarget() && !Util.ChainContainsCard(_CardId.EvenlyMatched)))
+ {
+ decideToActivate = true;
+ }
+
+ if (decideToActivate)
+ {
+ foreach (int checkId in checkListForSpSummon)
+ {
+ int checkTarget = CheckExosisterMentionCard(checkId);
+ if (checkTarget > 0 && CheckRemainInDeck(checkId) > 0 && CheckRemainInDeck(checkTarget) > 0)
+ {
+ if (checkTransform)
+ {
+ int canTransformCount = 0;
+ foreach (int transformCheckId in new List { checkId, checkTarget })
+ {
+ if (!Bot.HasInMonstersZone(checkId) && !exosisterTransformEffectList.Contains(checkId))
+ {
+ canTransformCount++;
+ }
+ }
+
+ if (canTransformCount == 0)
+ {
+ continue;
+ }
+ }
+ oncePerTurnEffectActivatedList.Add(Card.Id);
+ Logger.DebugWriteLine("Exosiseter Vadis decide: " + checkId);
+ AI.SelectCard(checkId);
+ AI.SelectNextCard(checkTarget);
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public bool ExosisterReturniaActivate()
+ {
+ if (Bot.LifePoints <= 800)
+ {
+ return false;
+ }
+
+ // banish problem card
+ ClientCard target = GetProblematicEnemyCard(true);
+ if (target != null && Duel.LastChainPlayer != 0)
+ {
+ Logger.DebugWriteLine("===Exosister: returnia target 1: " + target?.Name);
+ removeChosenList.Add(target);
+ oncePerTurnEffectActivatedList.Add(Card.Id);
+ AI.SelectCard(target);
+ return true;
+ }
+
+ // banish target
+ if (Duel.LastChainPlayer == 1)
+ {
+ List targetList = Duel.LastChainTargets.Where(card => card.Controller == 1 &&
+ (card.Location == CardLocation.Grave || card.Location == CardLocation.MonsterZone || card.Location == CardLocation.SpellZone || card.Location == CardLocation.FieldZone)).ToList();
+ if (targetList.Count() > 0)
+ {
+ oncePerTurnEffectActivatedList.Add(Card.Id);
+ List shuffleTargetList = ShuffleCardList(targetList);
+ Logger.DebugWriteLine("===Exosister: returnia target 2: " + shuffleTargetList[0]?.Name);
+ AI.SelectCard(shuffleTargetList);
+ return true;
+ }
+ }
+
+ // dump banish
+ target = GetBestEnemyCard(false, true, true);
+ bool check1 = DefaultOnBecomeTarget() && target != null && (target.Location != CardLocation.Onfield || target.Id != _CardId.EvenlyMatched);
+ bool check2 = Bot.UnderAttack;
+ bool check3 = (Duel.Player == 1 && Duel.Phase == DuelPhase.End && Duel.LastChainPlayer != 0 && target != null && target.Location != CardLocation.Grave);
+ bool check4 = (Duel.Player == 1 && Enemy.GetMonsterCount() >= 2 && Duel.LastChainPlayer != 0);
+ Logger.DebugWriteLine("===Exosister: returnia check flag: " + check1 + " " + check2 + " " + check3 + " " + check4);
+ if (check1 || check2 || check3 || check4)
+ {
+ oncePerTurnEffectActivatedList.Add(Card.Id);
+ Logger.DebugWriteLine("===Exosister: returnia target 3: " + target?.Name);
+ AI.SelectCard(target);
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Check hand like exosister + elis + martha
+ ///
+ public bool ExosisterAvoidMaxxCSummonCheck()
+ {
+ if (!Bot.HasInHand(CardId.ExosisterMartha) || !Bot.HasInHand(CardId.ExosisterElis) || elisEffect1Activated || marthaEffect1Activated)
+ {
+ return false;
+ }
+ if (enemyActivateLockBird && CheckAtAdvantage())
+ {
+ return false;
+ }
+ // normal summon non-elis exosister
+ if (Card.Id != CardId.ExosisterElis && Card.Id != CardId.ExosisterMartha)
+ {
+ summoned = true;
+ return true;
+ }
+ // normal summon elis
+ if (Card.IsCode(CardId.ExosisterElis))
+ {
+ int otherExosisterCount = Bot.Hand.Count(card => card?.Data != null && !card.IsCode(CardId.ExosisterElis) && !card.IsCode(CardId.ExosisterMartha)
+ && card.IsMonster() && card.HasSetcode(SetcodeExosister));
+ if (otherExosisterCount > 0)
+ {
+ return false;
+ }
+ if (Bot.Hand.Count(card => card?.Data != null && card.IsCode(CardId.ExosisterElis)) > 1)
+ {
+ summoned = true;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ ///
+ /// Check hand like exosister + stella
+ ///
+ public bool ExosisterStellaSummonCheck()
+ {
+ if (stellaEffect1Activated || Bot.HasInMonstersZone(CardId.ExosisterStella, true) || CheckWhetherNegated(true) || CheckLessOperation())
+ {
+ return false;
+ }
+ if (enemyActivateLockBird && CheckAtAdvantage())
+ {
+ return false;
+ }
+
+ int summonableCount = Bot.Hand.Count(card => card != Card && card?.Data != null && card.IsMonster()
+ && card.HasSetcode(SetcodeExosister));
+
+ if (summonableCount > 0)
+ {
+ summoned = true;
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Check whether need Irene's redraw effect to search elis for xyz
+ ///
+ public bool ExosisterIreneSummonCheck()
+ {
+ if (irenaEffect1Activated || CheckLessOperation()
+ || CheckWhetherNegated(true) || CheckCalledbytheGrave(CardId.ExosisterElis) > 0 || CheckCalledbytheGrave(CardId.ExosisterIrene) > 0)
+ {
+ return false;
+ }
+ if (enemyActivateLockBird && CheckAtAdvantage())
+ {
+ return false;
+ }
+
+ if (CheckRemainInDeck(CardId.ExosisterElis) > 0)
+ {
+ summoned = true;
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Check hand like exosister + elis
+ ///
+ public bool ExosisterForElisSummonCheck()
+ {
+ if (elisEffect1Activated || CheckCalledbytheGrave(CardId.ExosisterElis) > 0 || CheckLessOperation())
+ {
+ return false;
+ }
+ if (Card?.Data == null)
+ {
+ return false;
+ }
+ if (!Card.HasSetcode(SetcodeExosister) || (Card.IsCode(CardId.ExosisterMartha) && CheckRemainInDeck(CardId.ExosisterElis) > 0))
+ {
+ return false;
+ }
+ if (enemyActivateLockBird && CheckAtAdvantage())
+ {
+ return false;
+ }
+
+ if (Bot.Hand.Count(card => card != Card && card?.Data != null && card.IsCode(CardId.ExosisterElis)) > 0)
+ {
+ summoned = true;
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool AratamaSummonCheck()
+ {
+ if (sakitamaEffect1Activated || CheckCalledbytheGrave(CardId.Aratama) > 0 || CheckCalledbytheGrave(CardId.Sakitama) > 0)
+ {
+ return false;
+ }
+ if (enemyActivateLockBird && CheckAtAdvantage())
+ {
+ return false;
+ }
+ if (CheckRemainInDeck(CardId.Sakitama) > 0)
+ {
+ summoned = true;
+ return true;
+ }
+ return false;
+ }
+
+ public bool ForSakitamaSummonCheck()
+ {
+ if (sakitamaEffect1Activated || CheckCalledbytheGrave(CardId.Sakitama) > 0 || CheckLessOperation())
+ {
+ return false;
+ }
+ if (Bot.Hand.Count(card => card?.Data != null && Card != card && card.IsCode(CardId.Sakitama)) == 0)
+ {
+ return false;
+ }
+ if (enemyActivateLockBird && CheckAtAdvantage())
+ {
+ return false;
+ }
+ if (Card?.Data != null && !Card.IsCode(CardId.ExosisterMartha) && Card.Level == 4)
+ {
+ summoned = true;
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool Level4SummonCheck()
+ {
+ if (Card.Id == CardId.ExosisterMartha)
+ {
+ return false;
+ }
+ if (Bot.GetMonsters().Count(card => CheckAbleForXyz(card)) == 1)
+ {
+ summoned = true;
+ return true;
+ }
+ return false;
+ }
+
+ public bool ForDonnerSummonCheck()
+ {
+ if (!Bot.HasInExtra(CardId.DonnerDaggerFurHire) || (!Bot.HasInHand(CardId.ExosisterMartha) && !Bot.HasInHandOrInSpellZone(CardId.ExosisterReturnia)))
+ {
+ return false;
+ }
+ if (CheckLessOperation())
+ {
+ return false;
+ }
+
+ List illegalList = Bot.GetMonsters().Where(card => card.IsFaceup() && !card.HasType(CardType.Xyz) && card.Level != 4
+ && (card.Data == null || !card.HasSetcode(SetcodeExosister))).ToList();
+ if (illegalList.Count() == 0)
+ {
+ return false;
+ }
+
+ if (illegalList.Count() == 1)
+ {
+ List otherMaterialList = Bot.GetMonsters().Where(card => card.IsFaceup() && !card.HasType(CardType.Xyz)).ToList();
+ otherMaterialList.Sort(CardContainer.CompareCardAttack);
+ illegalList.AddRange(otherMaterialList);
+ }
+ if (illegalList.Count() == 1)
+ {
+ List hands = Bot.Hand.Where(card => card?.Data != null && card.IsMonster()).ToList();
+ if (hands.Count() > 0)
+ {
+ hands.Sort(CardContainer.CompareCardAttack);
+ if (Card != hands[0])
+ {
+ return false;
+ }
+ }
+ Logger.DebugWriteLine("===Exosister: summon for donner");
+ summoned = true;
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool ExosisterForArmentSummonCheck()
+ {
+ if (!Bot.HasInHandOrInSpellZone(CardId.ExosisterArment))
+ {
+ return false;
+ }
+ if (Card?.Data == null)
+ {
+ return false;
+ }
+ if (!Card.HasSetcode(SetcodeExosister))
+ {
+ return false;
+ }
+
+ if (!Bot.GetMonsters().Any(card => card?.Data != null && card.IsFaceup() && card.HasSetcode(SetcodeExosister)))
+ {
+ summoned = true;
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool ExosisterMikailisSpSummonCheck()
+ {
+ return ExosisterMikailisSpSummonCheckInner(true);
+ }
+
+ public bool ExosisterMikailisAdvancedSpSummonCheck()
+ {
+ if (!CheckLessOperation() || enemyActivateLockBird)
+ {
+ return false;
+ }
+
+ return ExosisterMikailisSpSummonCheckInner(false);
+ }
+
+ public bool ExosisterMikailisSpSummonCheckInner(bool shouldCheckLessOperation = true)
+ {
+ if (Bot.HasInMonstersZone(CardId.ExosisterMikailis) || mikailisEffect3Activated || (CheckLessOperation() && shouldCheckLessOperation))
+ {
+ return false;
+ }
+
+ // check searched spell/trap
+ if (!enemyActivateLockBird)
+ {
+ foreach (int cardId in ExosisterSpellTrapList)
+ {
+ if (!Bot.HasInHandOrInSpellZone(cardId))
+ {
+ SelectXyzMaterial(2);
+ return true;
+ }
+ }
+ }
+
+ // clear enemy card
+ if (!mikailisEffect1Activated && !Bot.HasInMonstersZone(CardId.ExosisterMikailis))
+ {
+ ClientCard target = GetProblematicEnemyCard(true);
+ if (target != null)
+ {
+ List exosisterMaterialList = Bot.GetMonsters().Where(card => CheckAbleForXyz(card) && card.HasSetcode(SetcodeExosister)).ToList();
+ if (exosisterMaterialList?.Count() > 0)
+ {
+ SelectXyzMaterial(2, true);
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public bool ExosisterKaspitellSpSummonCheck()
+ {
+ return ExosisterKaspitellSpSummonCheckInner(true);
+ }
+
+ public bool ExosisterKaspitellAdvancedSpSummonCheck()
+ {
+ if (!CheckLessOperation() || enemyActivateLockBird)
+ {
+ return false;
+ }
+ return ExosisterKaspitellSpSummonCheckInner(false);
+ }
+
+ public bool ExosisterKaspitellSpSummonCheckInner(bool shouldCheckLessOperation = true)
+ {
+ if (Bot.HasInMonstersZone(CardId.ExosisterKaspitell) || kaspitellEffect3Activated || (shouldCheckLessOperation && CheckLessOperation()))
+ {
+ return false;
+ }
+
+ bool searchMartha = true;
+ bool searchStella = true;
+ bool forMagnifica = false;
+ if (marthaEffect1Activated || CheckCalledbytheGrave(CardId.ExosisterMartha) > 0
+ || CheckRemainInDeck(CardId.ExosisterMartha) == 0 || CheckRemainInDeck(CardId.ExosisterElis) == 0)
+ {
+ searchMartha = false;
+ }
+ if (Bot.GetMonsters().Any(card => card.HasType(CardType.Link) || card.HasType(CardType.Token)))
+ {
+ searchMartha = false;
+ }
+ if (stellaEffect1Activated || CheckCalledbytheGrave(CardId.ExosisterStella) > 0 || CheckRemainInDeck(CardId.ExosisterStella) == 0
+ || !Bot.Hand.Any(card => card?.Data != null && card.IsMonster() && card.HasSetcode(SetcodeExosister)))
+ {
+ searchStella = false;
+ }
+ if (Bot.GetMonsters().Count(card => card?.Data != null
+ && card.HasType(CardType.Xyz) && card.HasType(CardType.Xyz) && !card.IsCode(CardId.ExosistersMagnifica)) == 1)
+ {
+ forMagnifica = true;
+ }
+ if (enemyActivateLockBird)
+ {
+ searchMartha = false;
+ searchStella = false;
+ }
+
+ if (!searchMartha && !searchStella && !forMagnifica)
+ {
+ return false;
+ }
+
+ List materialCheckList = Bot.GetMonsters().Where(card =>
+ !card.HasType(CardType.Xyz) && !card.HasType(CardType.Token) && !card.HasType(CardType.Link)).ToList();
+ if (materialCheckList.Count() == 2 && materialCheckList.All(card => card.Level == 4))
+ {
+ SelectXyzMaterial(2);
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool ExosistersMagnificaSpSummonCheck()
+ {
+ if (CheckLessOperation())
+ {
+ return false;
+ }
+
+ List materialList = Bot.GetMonsters().Where(card => card.IsFaceup() && card.HasType(CardType.Xyz)
+ && card.Rank == 4 && card.HasSetcode(SetcodeExosister)).ToList();
+ materialList.Sort(CardContainer.CompareCardAttack);
+
+ AI.SelectMaterials(materialList);
+ return true;
+ }
+
+ public bool CheckCaduceusInner(ClientCard card)
+ {
+ if (card?.Data == null)
+ {
+ return false;
+ }
+ foreach (int setcode in SetcodeForDiamond)
+ {
+ if (card.HasSetcode(setcode))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public bool TellarknightConstellarCaduceusSpSummonCheck()
+ {
+ if (Duel.Turn == 1 || !Bot.HasInExtra(CardId.StellarknightConstellarDiamond))
+ {
+ return false;
+ }
+
+ // check whether need to call Diamond
+ if (Enemy.Graveyard.Any(card => CheckCaduceusInner(card)))
+ {
+ SelectXyzMaterial(2);
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool DonnerDaggerFurHireSpSummonCheck()
+ {
+ if (!Bot.HasInHand(CardId.ExosisterMartha) && !Bot.HasInHandOrInSpellZone(CardId.ExosisterReturnia))
+ {
+ return false;
+ }
+
+ if (CheckLessOperation())
+ {
+ return false;
+ }
+
+ List illegalList = Bot.GetMonsters().Where(card => card.IsFaceup() && !card.HasType(CardType.Xyz) && card.Level != 4
+ && (card.Data == null || !card.HasSetcode(SetcodeExosister))).ToList();
+
+ if (illegalList.Count() == 1)
+ {
+
+ List otherMaterialList = Bot.GetMonsters().Where(card => card.IsFaceup() && !card.HasType(CardType.Xyz)).ToList();
+ otherMaterialList.Sort(CardContainer.CompareCardAttack);
+ illegalList.AddRange(otherMaterialList);
+ }
+ if (illegalList.Count() > 1)
+ {
+ AI.SelectMaterials(illegalList);
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool SpellSetCheck()
+ {
+ if (Duel.Phase == DuelPhase.Main1 && Bot.HasAttackingMonster() && Duel.Turn > 1) return false;
+ List onlyOneSetList = new List{
+ CardId.ExosisterPax, CardId.ExosisterArment, CardId.ExosisterVadis, CardId.ExosisterReturnia
+ };
+ if (onlyOneSetList.Contains(Card.Id) && Bot.HasInSpellZone(Card.Id))
+ {
+ return false;
+ }
+
+ // select place
+ if ((Card.IsTrap() || Card.HasType(CardType.QuickPlay)))
+ {
+ List avoid_list = 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)
+ {
+ avoid_list.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, avoid_list);
+ return true;
+ }
+ }
+ else
+ {
+ SelectSTPlace();
+ }
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/Game/AI/Decks/LabrynthExecutor.cs b/Game/AI/Decks/LabrynthExecutor.cs
new file mode 100644
index 00000000..548eb159
--- /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, long 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