diff --git a/ExecutorBase/ExecutorBase.csproj b/ExecutorBase/ExecutorBase.csproj
new file mode 100644
index 00000000..3062e851
--- /dev/null
+++ b/ExecutorBase/ExecutorBase.csproj
@@ -0,0 +1,89 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {A1583FD7-7985-47DD-A835-8134DBF5811C}
+ Library
+ Properties
+ ExecutorBase
+ ExecutorBase
+ v4.0
+ 512
+ true
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\Mono.Data.Sqlite.dll
+
+
+
+
+
+
+
+
+
+
+
+ ..\YGOSharp.OCGWrapper.dll
+
+
+ ..\YGOSharp.OCGWrapper.Enums.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Game/AI/AIUtil.cs b/ExecutorBase/Game/AI/AIUtil.cs
similarity index 97%
rename from Game/AI/AIUtil.cs
rename to ExecutorBase/Game/AI/AIUtil.cs
index eeeb8bf0..ab9f50f9 100644
--- a/Game/AI/AIUtil.cs
+++ b/ExecutorBase/Game/AI/AIUtil.cs
@@ -1,446 +1,446 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using YGOSharp.OCGWrapper.Enums;
-namespace WindBot.Game.AI
-{
- public class AIUtil
- {
- public Duel Duel { get; private set; }
- public ClientField Bot { get; private set; }
- public ClientField Enemy { get; private set; }
-
- public AIUtil(Duel duel)
- {
- Duel = duel;
- Bot = Duel.Fields[0];
- Enemy = Duel.Fields[1];
- }
-
- ///
- /// Get the total ATK Monster of the player.
- ///
- public int GetTotalAttackingMonsterAttack(int player)
- {
- return Duel.Fields[player].GetMonsters().Where(m => m.IsAttack()).Sum(m => (int?)m.Attack) ?? 0;
- }
- ///
- /// Get the best ATK or DEF power of the field.
- ///
- /// Bot or Enemy.
- /// Only calculate attack.
- public int GetBestPower(ClientField field, bool onlyATK = false)
- {
- return field.MonsterZone.GetMonsters()
- .Where(card => !onlyATK || card.IsAttack())
- .Max(card => (int?)card.GetDefensePower()) ?? -1;
- }
-
- public int GetBestAttack(ClientField field)
- {
- return GetBestPower(field, true);
- }
-
- public bool IsOneEnemyBetterThanValue(int value, bool onlyATK)
- {
- return Enemy.MonsterZone.GetMonsters()
- .Any(card => card.GetDefensePower() > value && (!onlyATK || card.IsAttack()));
- }
-
- public bool IsAllEnemyBetterThanValue(int value, bool onlyATK)
- {
- List monsters = Enemy.MonsterZone.GetMonsters();
- return monsters.Count > 0 && monsters
- .All(card => card.GetDefensePower() > value && (!onlyATK || card.IsAttack()));
- }
-
- ///
- /// Deprecated, use IsOneEnemyBetter and IsAllEnemyBetter instead.
- ///
- public bool IsEnemyBetter(bool onlyATK, bool all)
- {
- if (all)
- return IsAllEnemyBetter(onlyATK);
- else
- return IsOneEnemyBetter(onlyATK);
- }
-
- ///
- /// Is there an enemy monster who has better power than the best power of the bot's?
- ///
- /// Only calculate attack.
- public bool IsOneEnemyBetter(bool onlyATK = false)
- {
- int bestBotPower = GetBestPower(Bot, onlyATK);
- return IsOneEnemyBetterThanValue(bestBotPower, onlyATK);
- }
-
- ///
- /// Do all enemy monsters have better power than the best power of the bot's?
- ///
- /// Only calculate attack.
- public bool IsAllEnemyBetter(bool onlyATK = false)
- {
- int bestBotPower = GetBestPower(Bot, onlyATK);
- return IsAllEnemyBetterThanValue(bestBotPower, onlyATK);
- }
-
- public ClientCard GetBestBotMonster(bool onlyATK = false)
- {
- return Bot.MonsterZone.GetMonsters()
- .Where(card => !onlyATK || card.IsAttack())
- .OrderByDescending(card => card.GetDefensePower())
- .FirstOrDefault();
- }
-
- public ClientCard GetWorstBotMonster(bool onlyATK = false)
- {
- return Bot.MonsterZone.GetMonsters()
- .Where(card => !onlyATK || card.IsAttack())
- .OrderBy(card => card.GetDefensePower())
- .FirstOrDefault();
- }
-
- public ClientCard GetOneEnemyBetterThanValue(int value, bool onlyATK = false, bool canBeTarget = false)
- {
- return Enemy.MonsterZone.GetMonsters()
- .FirstOrDefault(card => card.GetDefensePower() >= value && (!onlyATK || card.IsAttack()) && (!canBeTarget || !card.IsShouldNotBeTarget()));
- }
-
- public ClientCard GetOneEnemyBetterThanMyBest(bool onlyATK = false, bool canBeTarget = false)
- {
- int bestBotPower = GetBestPower(Bot, onlyATK);
- return GetOneEnemyBetterThanValue(bestBotPower, onlyATK, canBeTarget);
- }
-
- public ClientCard GetProblematicEnemyCard(int attack = 0, bool canBeTarget = false)
- {
- ClientCard card = Enemy.MonsterZone.GetFloodgate(canBeTarget);
- if (card != null)
- return card;
-
- card = Enemy.SpellZone.GetFloodgate(canBeTarget);
- if (card != null)
- return card;
-
- card = Enemy.MonsterZone.GetDangerousMonster(canBeTarget);
- if (card != null)
- return card;
-
- card = Enemy.MonsterZone.GetInvincibleMonster(canBeTarget);
- if (card != null)
- return card;
-
- if (attack == 0)
- attack = GetBestAttack(Bot);
- return GetOneEnemyBetterThanValue(attack, true, canBeTarget);
- }
-
- public ClientCard GetProblematicEnemyMonster(int attack = 0, bool canBeTarget = false)
- {
- ClientCard card = Enemy.MonsterZone.GetFloodgate(canBeTarget);
- if (card != null)
- return card;
-
- card = Enemy.MonsterZone.GetDangerousMonster(canBeTarget);
- if (card != null)
- return card;
-
- card = Enemy.MonsterZone.GetInvincibleMonster(canBeTarget);
- if (card != null)
- return card;
-
- if (attack == 0)
- attack = GetBestAttack(Bot);
- return GetOneEnemyBetterThanValue(attack, true, canBeTarget);
- }
-
- public ClientCard GetProblematicEnemySpell()
- {
- ClientCard card = Enemy.SpellZone.GetFloodgate();
- return card;
- }
-
- public ClientCard GetBestEnemyCard(bool onlyFaceup = false, bool canBeTarget = false)
- {
- ClientCard card = GetBestEnemyMonster(onlyFaceup, canBeTarget);
- if (card != null)
- return card;
-
- card = GetBestEnemySpell(onlyFaceup);
- if (card != null)
- return card;
-
- 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 monsters[0];
-
- return null;
- }
-
- public ClientCard GetWorstEnemyMonster(bool onlyATK = false)
- {
- return Enemy.MonsterZone.GetMonsters()
- .Where(card => !onlyATK || card.IsAttack())
- .OrderBy(card => card.GetDefensePower())
- .FirstOrDefault();
- }
-
- public ClientCard GetBestEnemySpell(bool onlyFaceup = false)
- {
- ClientCard card = GetProblematicEnemySpell();
- if (card != null)
- return card;
-
- var spells = Enemy.GetSpells();
-
- card = spells.FirstOrDefault(ecard => ecard.IsFaceup() && (ecard.HasType(CardType.Continuous) || ecard.HasType(CardType.Field)));
- if (card != null)
- return card;
-
- if (spells.Count > 0 && !onlyFaceup)
- return spells[0];
-
- return null;
- }
-
- public ClientCard GetPZone(int player, int id)
- {
- if (Duel.IsNewRule)
- {
- return Duel.Fields[player].SpellZone[id * 4];
- }
- else
- {
- return Duel.Fields[player].SpellZone[6 + id];
- }
- }
-
- public int GetStringId(int id, int option)
- {
- return id * 16 + option;
- }
-
- public bool IsTurn1OrMain2()
- {
- return Duel.Turn == 1 || Duel.Phase == DuelPhase.Main2;
- }
-
- public int GetBotAvailZonesFromExtraDeck(IList remove)
- {
- ClientCard[] BotMZone = (ClientCard[])Bot.MonsterZone.Clone();
- ClientCard[] EnemyMZone = (ClientCard[])Enemy.MonsterZone.Clone();
- for (int i = 0; i < 7; i++)
- {
- if (remove.Contains(BotMZone[i])) BotMZone[i] = null;
- if (remove.Contains(EnemyMZone[i])) EnemyMZone[i] = null;
- }
-
- if (!Duel.IsNewRule || Duel.IsNewRule2020)
- return Zones.MainMonsterZones;
-
- int result = 0;
-
- if (BotMZone[5] == null && BotMZone[6] == null)
- {
- if (EnemyMZone[5] == null)
- result |= Zones.z6;
- if (EnemyMZone[6] == null)
- result |= Zones.z5;
- }
-
- if (BotMZone[0] == null &&
- ((BotMZone[1]?.HasLinkMarker(CardLinkMarker.Left) ?? false) ||
- (BotMZone[5]?.HasLinkMarker(CardLinkMarker.BottomLeft) ?? false) ||
- (EnemyMZone[6]?.HasLinkMarker(CardLinkMarker.TopRight) ?? false)))
- result |= Zones.z0;
-
- if (BotMZone[1] == null &&
- ((BotMZone[0]?.HasLinkMarker(CardLinkMarker.Right) ?? false) ||
- (BotMZone[2]?.HasLinkMarker(CardLinkMarker.Left) ?? false) ||
- (BotMZone[5]?.HasLinkMarker(CardLinkMarker.Bottom) ?? false) ||
- (EnemyMZone[6]?.HasLinkMarker(CardLinkMarker.Top) ?? false)))
- result |= Zones.z1;
-
- if (BotMZone[2] == null &&
- ((BotMZone[1]?.HasLinkMarker(CardLinkMarker.Right) ?? false) ||
- (BotMZone[3]?.HasLinkMarker(CardLinkMarker.Left) ?? false) ||
- (BotMZone[5]?.HasLinkMarker(CardLinkMarker.BottomRight) ?? false) ||
- (EnemyMZone[6]?.HasLinkMarker(CardLinkMarker.TopLeft) ?? false) ||
- (BotMZone[6]?.HasLinkMarker(CardLinkMarker.BottomLeft) ?? false) ||
- (EnemyMZone[5]?.HasLinkMarker(CardLinkMarker.TopRight) ?? false)))
- result |= Zones.z2;
-
- if (BotMZone[3] == null &&
- ((BotMZone[2]?.HasLinkMarker(CardLinkMarker.Right) ?? false) ||
- (BotMZone[4]?.HasLinkMarker(CardLinkMarker.Left) ?? false) ||
- (BotMZone[6]?.HasLinkMarker(CardLinkMarker.Bottom) ?? false) ||
- (EnemyMZone[5]?.HasLinkMarker(CardLinkMarker.Top) ?? false)))
- result |= Zones.z3;
-
- if (BotMZone[4] == null &&
- ((BotMZone[3]?.HasLinkMarker(CardLinkMarker.Right) ?? false) ||
- (BotMZone[6]?.HasLinkMarker(CardLinkMarker.BottomRight) ?? false) ||
- (EnemyMZone[5]?.HasLinkMarker(CardLinkMarker.TopLeft) ?? false)))
- result |= Zones.z4;
-
- return result;
- }
-
- public int GetBotAvailZonesFromExtraDeck(ClientCard remove)
- {
- return GetBotAvailZonesFromExtraDeck(new[] { remove });
- }
-
- public int GetBotAvailZonesFromExtraDeck()
- {
- return GetBotAvailZonesFromExtraDeck(new List());
- }
-
- public bool IsChainTarget(ClientCard card)
- {
- return Duel.ChainTargets.Any(card.Equals);
- }
-
- public bool IsChainTargetOnly(ClientCard card)
- {
- return Duel.ChainTargetOnly.Count == 1 && card.Equals(Duel.ChainTargetOnly[0]);
- }
-
- public bool ChainContainsCard(int id)
- {
- return Duel.CurrentChain.Any(card => card.IsCode(id));
- }
-
- public bool ChainContainsCard(int[] ids)
- {
- return Duel.CurrentChain.Any(card => card.IsCode(ids));
- }
-
- public int ChainCountPlayer(int player)
- {
- return Duel.CurrentChain.Count(card => card.Controller == player);
- }
-
- public bool ChainContainPlayer(int player)
- {
- return Duel.CurrentChain.Any(card => card.Controller == player);
- }
-
- public bool HasChainedTrap(int player)
- {
- return Duel.CurrentChain.Any(card => card.Controller == player && card.HasType(CardType.Trap));
- }
-
- public ClientCard GetLastChainCard()
- {
- return Duel.CurrentChain.LastOrDefault();
- }
-
- ///
- /// Select cards listed in preferred.
- ///
- public IList SelectPreferredCards(ClientCard preferred, IList cards, int min, int max)
- {
- IList selected = new List();
- if (cards.IndexOf(preferred) > 0 && selected.Count < max)
- {
- selected.Add(preferred);
- }
-
- return selected;
- }
-
- ///
- /// Select cards listed in preferred.
- ///
- public IList SelectPreferredCards(int preferred, IList cards, int min, int max)
- {
- IList selected = new List();
- foreach (ClientCard card in cards)
- {
- if (card.IsCode(preferred) && selected.Count < max)
- selected.Add(card);
- }
-
- return selected;
- }
-
- ///
- /// Select cards listed in preferred.
- ///
- public IList SelectPreferredCards(IList preferred, IList cards, int min, int max)
- {
- IList selected = new List();
- IList avail = cards.ToList(); // clone
- while (preferred.Count > 0 && avail.IndexOf(preferred[0]) > 0 && selected.Count < max)
- {
- ClientCard card = preferred[0];
- preferred.Remove(card);
- avail.Remove(card);
- selected.Add(card);
- }
-
- return selected;
- }
-
- ///
- /// Select cards listed in preferred.
- ///
- public IList SelectPreferredCards(IList preferred, IList cards, int min, int max)
- {
- IList selected = new List();
- foreach (int id in preferred)
- {
- foreach (ClientCard card in cards)
- {
- if (card.IsCode(id) && selected.Count < max && selected.IndexOf(card) <= 0)
- selected.Add(card);
- }
- if (selected.Count >= max)
- break;
- }
-
- return selected;
- }
-
- ///
- /// Check and fix selected to make sure it meet the count requirement.
- ///
- public IList CheckSelectCount(IList _selected, IList cards, int min, int max)
- {
- var selected = _selected.ToList();
- if (selected.Count < min)
- {
- foreach (ClientCard card in cards)
- {
- if (!selected.Contains(card))
- selected.Add(card);
- if (selected.Count >= max)
- break;
- }
- }
- while (selected.Count > max)
- {
- selected.RemoveAt(selected.Count - 1);
- }
-
- return selected;
- }
- }
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using YGOSharp.OCGWrapper.Enums;
+namespace WindBot.Game.AI
+{
+ public class AIUtil
+ {
+ public Duel Duel { get; private set; }
+ public ClientField Bot { get; private set; }
+ public ClientField Enemy { get; private set; }
+
+ public AIUtil(Duel duel)
+ {
+ Duel = duel;
+ Bot = Duel.Fields[0];
+ Enemy = Duel.Fields[1];
+ }
+
+ ///
+ /// Get the total ATK Monster of the player.
+ ///
+ public int GetTotalAttackingMonsterAttack(int player)
+ {
+ return Duel.Fields[player].GetMonsters().Where(m => m.IsAttack()).Sum(m => (int?)m.Attack) ?? 0;
+ }
+ ///
+ /// Get the best ATK or DEF power of the field.
+ ///
+ /// Bot or Enemy.
+ /// Only calculate attack.
+ public int GetBestPower(ClientField field, bool onlyATK = false)
+ {
+ return field.MonsterZone.GetMonsters()
+ .Where(card => !onlyATK || card.IsAttack())
+ .Max(card => (int?)card.GetDefensePower()) ?? -1;
+ }
+
+ public int GetBestAttack(ClientField field)
+ {
+ return GetBestPower(field, true);
+ }
+
+ public bool IsOneEnemyBetterThanValue(int value, bool onlyATK)
+ {
+ return Enemy.MonsterZone.GetMonsters()
+ .Any(card => card.GetDefensePower() > value && (!onlyATK || card.IsAttack()));
+ }
+
+ public bool IsAllEnemyBetterThanValue(int value, bool onlyATK)
+ {
+ List monsters = Enemy.MonsterZone.GetMonsters();
+ return monsters.Count > 0 && monsters
+ .All(card => card.GetDefensePower() > value && (!onlyATK || card.IsAttack()));
+ }
+
+ ///
+ /// Deprecated, use IsOneEnemyBetter and IsAllEnemyBetter instead.
+ ///
+ public bool IsEnemyBetter(bool onlyATK, bool all)
+ {
+ if (all)
+ return IsAllEnemyBetter(onlyATK);
+ else
+ return IsOneEnemyBetter(onlyATK);
+ }
+
+ ///
+ /// Is there an enemy monster who has better power than the best power of the bot's?
+ ///
+ /// Only calculate attack.
+ public bool IsOneEnemyBetter(bool onlyATK = false)
+ {
+ int bestBotPower = GetBestPower(Bot, onlyATK);
+ return IsOneEnemyBetterThanValue(bestBotPower, onlyATK);
+ }
+
+ ///
+ /// Do all enemy monsters have better power than the best power of the bot's?
+ ///
+ /// Only calculate attack.
+ public bool IsAllEnemyBetter(bool onlyATK = false)
+ {
+ int bestBotPower = GetBestPower(Bot, onlyATK);
+ return IsAllEnemyBetterThanValue(bestBotPower, onlyATK);
+ }
+
+ public ClientCard GetBestBotMonster(bool onlyATK = false)
+ {
+ return Bot.MonsterZone.GetMonsters()
+ .Where(card => !onlyATK || card.IsAttack())
+ .OrderByDescending(card => card.GetDefensePower())
+ .FirstOrDefault();
+ }
+
+ public ClientCard GetWorstBotMonster(bool onlyATK = false)
+ {
+ return Bot.MonsterZone.GetMonsters()
+ .Where(card => !onlyATK || card.IsAttack())
+ .OrderBy(card => card.GetDefensePower())
+ .FirstOrDefault();
+ }
+
+ public ClientCard GetOneEnemyBetterThanValue(int value, bool onlyATK = false, bool canBeTarget = false)
+ {
+ return Enemy.MonsterZone.GetMonsters()
+ .FirstOrDefault(card => card.GetDefensePower() >= value && (!onlyATK || card.IsAttack()) && (!canBeTarget || !card.IsShouldNotBeTarget()));
+ }
+
+ public ClientCard GetOneEnemyBetterThanMyBest(bool onlyATK = false, bool canBeTarget = false)
+ {
+ int bestBotPower = GetBestPower(Bot, onlyATK);
+ return GetOneEnemyBetterThanValue(bestBotPower, onlyATK, canBeTarget);
+ }
+
+ public ClientCard GetProblematicEnemyCard(int attack = 0, bool canBeTarget = false)
+ {
+ ClientCard card = Enemy.MonsterZone.GetFloodgate(canBeTarget);
+ if (card != null)
+ return card;
+
+ card = Enemy.SpellZone.GetFloodgate(canBeTarget);
+ if (card != null)
+ return card;
+
+ card = Enemy.MonsterZone.GetDangerousMonster(canBeTarget);
+ if (card != null)
+ return card;
+
+ card = Enemy.MonsterZone.GetInvincibleMonster(canBeTarget);
+ if (card != null)
+ return card;
+
+ if (attack == 0)
+ attack = GetBestAttack(Bot);
+ return GetOneEnemyBetterThanValue(attack, true, canBeTarget);
+ }
+
+ public ClientCard GetProblematicEnemyMonster(int attack = 0, bool canBeTarget = false)
+ {
+ ClientCard card = Enemy.MonsterZone.GetFloodgate(canBeTarget);
+ if (card != null)
+ return card;
+
+ card = Enemy.MonsterZone.GetDangerousMonster(canBeTarget);
+ if (card != null)
+ return card;
+
+ card = Enemy.MonsterZone.GetInvincibleMonster(canBeTarget);
+ if (card != null)
+ return card;
+
+ if (attack == 0)
+ attack = GetBestAttack(Bot);
+ return GetOneEnemyBetterThanValue(attack, true, canBeTarget);
+ }
+
+ public ClientCard GetProblematicEnemySpell()
+ {
+ ClientCard card = Enemy.SpellZone.GetFloodgate();
+ return card;
+ }
+
+ public ClientCard GetBestEnemyCard(bool onlyFaceup = false, bool canBeTarget = false)
+ {
+ ClientCard card = GetBestEnemyMonster(onlyFaceup, canBeTarget);
+ if (card != null)
+ return card;
+
+ card = GetBestEnemySpell(onlyFaceup);
+ if (card != null)
+ return card;
+
+ 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 monsters[0];
+
+ return null;
+ }
+
+ public ClientCard GetWorstEnemyMonster(bool onlyATK = false)
+ {
+ return Enemy.MonsterZone.GetMonsters()
+ .Where(card => !onlyATK || card.IsAttack())
+ .OrderBy(card => card.GetDefensePower())
+ .FirstOrDefault();
+ }
+
+ public ClientCard GetBestEnemySpell(bool onlyFaceup = false)
+ {
+ ClientCard card = GetProblematicEnemySpell();
+ if (card != null)
+ return card;
+
+ var spells = Enemy.GetSpells();
+
+ card = spells.FirstOrDefault(ecard => ecard.IsFaceup() && (ecard.HasType(CardType.Continuous) || ecard.HasType(CardType.Field)));
+ if (card != null)
+ return card;
+
+ if (spells.Count > 0 && !onlyFaceup)
+ return spells[0];
+
+ return null;
+ }
+
+ public ClientCard GetPZone(int player, int id)
+ {
+ if (Duel.IsNewRule)
+ {
+ return Duel.Fields[player].SpellZone[id * 4];
+ }
+ else
+ {
+ return Duel.Fields[player].SpellZone[6 + id];
+ }
+ }
+
+ public int GetStringId(int id, int option)
+ {
+ return id * 16 + option;
+ }
+
+ public bool IsTurn1OrMain2()
+ {
+ return Duel.Turn == 1 || Duel.Phase == DuelPhase.Main2;
+ }
+
+ public int GetBotAvailZonesFromExtraDeck(IList remove)
+ {
+ ClientCard[] BotMZone = (ClientCard[])Bot.MonsterZone.Clone();
+ ClientCard[] EnemyMZone = (ClientCard[])Enemy.MonsterZone.Clone();
+ for (int i = 0; i < 7; i++)
+ {
+ if (remove.Contains(BotMZone[i])) BotMZone[i] = null;
+ if (remove.Contains(EnemyMZone[i])) EnemyMZone[i] = null;
+ }
+
+ if (!Duel.IsNewRule || Duel.IsNewRule2020)
+ return Zones.MainMonsterZones;
+
+ int result = 0;
+
+ if (BotMZone[5] == null && BotMZone[6] == null)
+ {
+ if (EnemyMZone[5] == null)
+ result |= Zones.z6;
+ if (EnemyMZone[6] == null)
+ result |= Zones.z5;
+ }
+
+ if (BotMZone[0] == null &&
+ ((BotMZone[1]?.HasLinkMarker(CardLinkMarker.Left) ?? false) ||
+ (BotMZone[5]?.HasLinkMarker(CardLinkMarker.BottomLeft) ?? false) ||
+ (EnemyMZone[6]?.HasLinkMarker(CardLinkMarker.TopRight) ?? false)))
+ result |= Zones.z0;
+
+ if (BotMZone[1] == null &&
+ ((BotMZone[0]?.HasLinkMarker(CardLinkMarker.Right) ?? false) ||
+ (BotMZone[2]?.HasLinkMarker(CardLinkMarker.Left) ?? false) ||
+ (BotMZone[5]?.HasLinkMarker(CardLinkMarker.Bottom) ?? false) ||
+ (EnemyMZone[6]?.HasLinkMarker(CardLinkMarker.Top) ?? false)))
+ result |= Zones.z1;
+
+ if (BotMZone[2] == null &&
+ ((BotMZone[1]?.HasLinkMarker(CardLinkMarker.Right) ?? false) ||
+ (BotMZone[3]?.HasLinkMarker(CardLinkMarker.Left) ?? false) ||
+ (BotMZone[5]?.HasLinkMarker(CardLinkMarker.BottomRight) ?? false) ||
+ (EnemyMZone[6]?.HasLinkMarker(CardLinkMarker.TopLeft) ?? false) ||
+ (BotMZone[6]?.HasLinkMarker(CardLinkMarker.BottomLeft) ?? false) ||
+ (EnemyMZone[5]?.HasLinkMarker(CardLinkMarker.TopRight) ?? false)))
+ result |= Zones.z2;
+
+ if (BotMZone[3] == null &&
+ ((BotMZone[2]?.HasLinkMarker(CardLinkMarker.Right) ?? false) ||
+ (BotMZone[4]?.HasLinkMarker(CardLinkMarker.Left) ?? false) ||
+ (BotMZone[6]?.HasLinkMarker(CardLinkMarker.Bottom) ?? false) ||
+ (EnemyMZone[5]?.HasLinkMarker(CardLinkMarker.Top) ?? false)))
+ result |= Zones.z3;
+
+ if (BotMZone[4] == null &&
+ ((BotMZone[3]?.HasLinkMarker(CardLinkMarker.Right) ?? false) ||
+ (BotMZone[6]?.HasLinkMarker(CardLinkMarker.BottomRight) ?? false) ||
+ (EnemyMZone[5]?.HasLinkMarker(CardLinkMarker.TopLeft) ?? false)))
+ result |= Zones.z4;
+
+ return result;
+ }
+
+ public int GetBotAvailZonesFromExtraDeck(ClientCard remove)
+ {
+ return GetBotAvailZonesFromExtraDeck(new[] { remove });
+ }
+
+ public int GetBotAvailZonesFromExtraDeck()
+ {
+ return GetBotAvailZonesFromExtraDeck(new List());
+ }
+
+ public bool IsChainTarget(ClientCard card)
+ {
+ return Duel.ChainTargets.Any(card.Equals);
+ }
+
+ public bool IsChainTargetOnly(ClientCard card)
+ {
+ return Duel.ChainTargetOnly.Count == 1 && card.Equals(Duel.ChainTargetOnly[0]);
+ }
+
+ public bool ChainContainsCard(int id)
+ {
+ return Duel.CurrentChain.Any(card => card.IsCode(id));
+ }
+
+ public bool ChainContainsCard(int[] ids)
+ {
+ return Duel.CurrentChain.Any(card => card.IsCode(ids));
+ }
+
+ public int ChainCountPlayer(int player)
+ {
+ return Duel.CurrentChain.Count(card => card.Controller == player);
+ }
+
+ public bool ChainContainPlayer(int player)
+ {
+ return Duel.CurrentChain.Any(card => card.Controller == player);
+ }
+
+ public bool HasChainedTrap(int player)
+ {
+ return Duel.CurrentChain.Any(card => card.Controller == player && card.HasType(CardType.Trap));
+ }
+
+ public ClientCard GetLastChainCard()
+ {
+ return Duel.CurrentChain.LastOrDefault();
+ }
+
+ ///
+ /// Select cards listed in preferred.
+ ///
+ public IList SelectPreferredCards(ClientCard preferred, IList cards, int min, int max)
+ {
+ IList selected = new List();
+ if (cards.IndexOf(preferred) > 0 && selected.Count < max)
+ {
+ selected.Add(preferred);
+ }
+
+ return selected;
+ }
+
+ ///
+ /// Select cards listed in preferred.
+ ///
+ public IList SelectPreferredCards(int preferred, IList cards, int min, int max)
+ {
+ IList selected = new List();
+ foreach (ClientCard card in cards)
+ {
+ if (card.IsCode(preferred) && selected.Count < max)
+ selected.Add(card);
+ }
+
+ return selected;
+ }
+
+ ///
+ /// Select cards listed in preferred.
+ ///
+ public IList SelectPreferredCards(IList preferred, IList cards, int min, int max)
+ {
+ IList selected = new List();
+ IList avail = cards.ToList(); // clone
+ while (preferred.Count > 0 && avail.IndexOf(preferred[0]) > 0 && selected.Count < max)
+ {
+ ClientCard card = preferred[0];
+ preferred.Remove(card);
+ avail.Remove(card);
+ selected.Add(card);
+ }
+
+ return selected;
+ }
+
+ ///
+ /// Select cards listed in preferred.
+ ///
+ public IList SelectPreferredCards(IList preferred, IList cards, int min, int max)
+ {
+ IList selected = new List();
+ foreach (int id in preferred)
+ {
+ foreach (ClientCard card in cards)
+ {
+ if (card.IsCode(id) && selected.Count < max && selected.IndexOf(card) <= 0)
+ selected.Add(card);
+ }
+ if (selected.Count >= max)
+ break;
+ }
+
+ return selected;
+ }
+
+ ///
+ /// Check and fix selected to make sure it meet the count requirement.
+ ///
+ public IList CheckSelectCount(IList _selected, IList cards, int min, int max)
+ {
+ var selected = _selected.ToList();
+ if (selected.Count < min)
+ {
+ foreach (ClientCard card in cards)
+ {
+ if (!selected.Contains(card))
+ selected.Add(card);
+ if (selected.Count >= max)
+ break;
+ }
+ }
+ while (selected.Count > max)
+ {
+ selected.RemoveAt(selected.Count - 1);
+ }
+
+ return selected;
+ }
+ }
}
\ No newline at end of file
diff --git a/Game/AI/CardContainer.cs b/ExecutorBase/Game/AI/CardContainer.cs
similarity index 97%
rename from Game/AI/CardContainer.cs
rename to ExecutorBase/Game/AI/CardContainer.cs
index 1b263e59..0a09a506 100644
--- a/Game/AI/CardContainer.cs
+++ b/ExecutorBase/Game/AI/CardContainer.cs
@@ -1,155 +1,155 @@
-using System.Collections.Generic;
-using YGOSharp.OCGWrapper.Enums;
-using System;
-using System.Linq;
-
-namespace WindBot.Game.AI
-{
- public static class CardContainer
- {
- public static int CompareCardAttack(ClientCard cardA, ClientCard cardB)
- {
- if (cardA.Attack < cardB.Attack)
- return -1;
- if (cardA.Attack == cardB.Attack)
- return 0;
- return 1;
- }
-
- public static int CompareCardLevel(ClientCard cardA, ClientCard cardB)
- {
- if (cardA.Level < cardB.Level)
- return -1;
- if (cardA.Level == cardB.Level)
- return 0;
- return 1;
- }
-
- public static int CompareDefensePower(ClientCard cardA, ClientCard cardB)
- {
- if (cardA == null && cardB == null)
- return 0;
- if (cardA == null)
- return -1;
- if (cardB == null)
- return 1;
- int powerA = cardA.GetDefensePower();
- int powerB = cardB.GetDefensePower();
- if (powerA < powerB)
- return -1;
- if (powerA == powerB)
- return 0;
- return 1;
- }
-
- public static ClientCard GetHighestAttackMonster(this IEnumerable cards, bool canBeTarget = false)
- {
- return cards
- .Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget()))
- .OrderBy(card => card.Attack).FirstOrDefault();
- }
-
- public static ClientCard GetHighestDefenseMonster(this IEnumerable cards, bool canBeTarget = false)
- {
- return cards
- .Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget()))
- .OrderBy(card => card.Defense).FirstOrDefault();
- }
-
- public static ClientCard GetLowestAttackMonster(this IEnumerable cards, bool canBeTarget = false)
- {
- return cards
- .Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget()))
- .OrderByDescending(card => card.Attack).FirstOrDefault();
- }
-
- public static ClientCard GetLowestDefenseMonster(this IEnumerable cards, bool canBeTarget = false)
- {
- return cards
- .Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget()))
- .OrderByDescending(card => card.Defense).FirstOrDefault();
- }
-
- public static bool ContainsMonsterWithLevel(this IEnumerable cards, int level)
- {
- return cards.Where(card => card?.Data != null).Any(card => !card.HasType(CardType.Xyz) && card.Level == level);
- }
-
- public static bool ContainsMonsterWithRank(this IEnumerable cards, int rank)
- {
- return cards.Where(card => card?.Data != null).Any(card => card.HasType(CardType.Xyz) && card.Rank == rank);
- }
-
- public static bool ContainsCardWithId(this IEnumerable cards, int id)
- {
- return cards.Where(card => card?.Data != null).Any(card => card.IsCode(id));
- }
-
- public static int GetCardCount(this IEnumerable cards, int id)
- {
- return cards.Where(card => card?.Data != null).Count(card => card.IsCode(id));
- }
-
- public static List GetMonsters(this IEnumerable cards)
- {
- return cards.Where(card => card?.Data != null && card.HasType(CardType.Monster)).ToList();
- }
-
- public static List GetFaceupPendulumMonsters(this IEnumerable cards)
- {
- return cards.Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && card.HasType(CardType.Pendulum)).ToList();
- }
-
- public static ClientCard GetInvincibleMonster(this IEnumerable cards, bool canBeTarget = false)
- {
- return cards.FirstOrDefault(card => card?.Data != null && card.IsMonsterInvincible() && card.IsFaceup() && (!canBeTarget || !card.IsShouldNotBeTarget()));
- }
-
- public static ClientCard GetDangerousMonster(this IEnumerable cards, bool canBeTarget = false)
- {
- return cards.FirstOrDefault(card => card?.Data != null && card.IsMonsterDangerous() && card.IsFaceup() && (!canBeTarget || !card.IsShouldNotBeTarget()));
- }
-
- public static ClientCard GetFloodgate(this IEnumerable cards, bool canBeTarget = false)
- {
- return cards.FirstOrDefault(card => card?.Data != null && card.IsFloodgate() && card.IsFaceup() && (!canBeTarget || !card.IsShouldNotBeTarget()));
- }
-
- public static ClientCard GetFirstMatchingCard(this IEnumerable cards, Func filter)
- {
- return cards.FirstOrDefault(card => card?.Data != null && filter.Invoke(card));
- }
-
- public static ClientCard GetFirstMatchingFaceupCard(this IEnumerable cards, Func filter)
- {
- return cards.FirstOrDefault(card => card?.Data != null && card.IsFaceup() && filter.Invoke(card));
- }
-
- public static IList GetMatchingCards(this IEnumerable cards, Func filter)
- {
- return cards.Where(card => card?.Data != null && filter.Invoke(card)).ToList();
- }
-
- public static int GetMatchingCardsCount(this IEnumerable cards, Func filter)
- {
- return cards.Count(card => card?.Data != null && filter.Invoke(card));
- }
-
- public static bool IsExistingMatchingCard(this IEnumerable cards, Func filter, int count = 1)
- {
- return cards.GetMatchingCardsCount(filter) >= count;
- }
-
- public static ClientCard GetShouldBeDisabledBeforeItUseEffectMonster(this IEnumerable cards, bool canBeTarget = true)
- {
- return cards.FirstOrDefault(card => card?.Data != null && card.IsMonsterShouldBeDisabledBeforeItUseEffect() && card.IsFaceup() && (!canBeTarget || !card.IsShouldNotBeTarget()));
- }
-
- public static IEnumerable> GetCombinations(this IEnumerable elements, int k)
- {
- return k == 0 ? new[] { new T[0] } :
- elements.SelectMany((e, i) =>
- elements.Skip(i + 1).GetCombinations(k - 1).Select(c => (new[] { e }).Concat(c)));
- }
- }
+using System.Collections.Generic;
+using YGOSharp.OCGWrapper.Enums;
+using System;
+using System.Linq;
+
+namespace WindBot.Game.AI
+{
+ public static class CardContainer
+ {
+ public static int CompareCardAttack(ClientCard cardA, ClientCard cardB)
+ {
+ if (cardA.Attack < cardB.Attack)
+ return -1;
+ if (cardA.Attack == cardB.Attack)
+ return 0;
+ return 1;
+ }
+
+ public static int CompareCardLevel(ClientCard cardA, ClientCard cardB)
+ {
+ if (cardA.Level < cardB.Level)
+ return -1;
+ if (cardA.Level == cardB.Level)
+ return 0;
+ return 1;
+ }
+
+ public static int CompareDefensePower(ClientCard cardA, ClientCard cardB)
+ {
+ if (cardA == null && cardB == null)
+ return 0;
+ if (cardA == null)
+ return -1;
+ if (cardB == null)
+ return 1;
+ int powerA = cardA.GetDefensePower();
+ int powerB = cardB.GetDefensePower();
+ if (powerA < powerB)
+ return -1;
+ if (powerA == powerB)
+ return 0;
+ return 1;
+ }
+
+ public static ClientCard GetHighestAttackMonster(this IEnumerable cards, bool canBeTarget = false)
+ {
+ return cards
+ .Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget()))
+ .OrderBy(card => card.Attack).FirstOrDefault();
+ }
+
+ public static ClientCard GetHighestDefenseMonster(this IEnumerable cards, bool canBeTarget = false)
+ {
+ return cards
+ .Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget()))
+ .OrderBy(card => card.Defense).FirstOrDefault();
+ }
+
+ public static ClientCard GetLowestAttackMonster(this IEnumerable cards, bool canBeTarget = false)
+ {
+ return cards
+ .Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget()))
+ .OrderByDescending(card => card.Attack).FirstOrDefault();
+ }
+
+ public static ClientCard GetLowestDefenseMonster(this IEnumerable cards, bool canBeTarget = false)
+ {
+ return cards
+ .Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget()))
+ .OrderByDescending(card => card.Defense).FirstOrDefault();
+ }
+
+ public static bool ContainsMonsterWithLevel(this IEnumerable cards, int level)
+ {
+ return cards.Where(card => card?.Data != null).Any(card => !card.HasType(CardType.Xyz) && card.Level == level);
+ }
+
+ public static bool ContainsMonsterWithRank(this IEnumerable cards, int rank)
+ {
+ return cards.Where(card => card?.Data != null).Any(card => card.HasType(CardType.Xyz) && card.Rank == rank);
+ }
+
+ public static bool ContainsCardWithId(this IEnumerable cards, int id)
+ {
+ return cards.Where(card => card?.Data != null).Any(card => card.IsCode(id));
+ }
+
+ public static int GetCardCount(this IEnumerable cards, int id)
+ {
+ return cards.Where(card => card?.Data != null).Count(card => card.IsCode(id));
+ }
+
+ public static List GetMonsters(this IEnumerable cards)
+ {
+ return cards.Where(card => card?.Data != null && card.HasType(CardType.Monster)).ToList();
+ }
+
+ public static List GetFaceupPendulumMonsters(this IEnumerable cards)
+ {
+ return cards.Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && card.HasType(CardType.Pendulum)).ToList();
+ }
+
+ public static ClientCard GetInvincibleMonster(this IEnumerable cards, bool canBeTarget = false)
+ {
+ return cards.FirstOrDefault(card => card?.Data != null && card.IsMonsterInvincible() && card.IsFaceup() && (!canBeTarget || !card.IsShouldNotBeTarget()));
+ }
+
+ public static ClientCard GetDangerousMonster(this IEnumerable cards, bool canBeTarget = false)
+ {
+ return cards.FirstOrDefault(card => card?.Data != null && card.IsMonsterDangerous() && card.IsFaceup() && (!canBeTarget || !card.IsShouldNotBeTarget()));
+ }
+
+ public static ClientCard GetFloodgate(this IEnumerable cards, bool canBeTarget = false)
+ {
+ return cards.FirstOrDefault(card => card?.Data != null && card.IsFloodgate() && card.IsFaceup() && (!canBeTarget || !card.IsShouldNotBeTarget()));
+ }
+
+ public static ClientCard GetFirstMatchingCard(this IEnumerable cards, Func filter)
+ {
+ return cards.FirstOrDefault(card => card?.Data != null && filter.Invoke(card));
+ }
+
+ public static ClientCard GetFirstMatchingFaceupCard(this IEnumerable cards, Func filter)
+ {
+ return cards.FirstOrDefault(card => card?.Data != null && card.IsFaceup() && filter.Invoke(card));
+ }
+
+ public static IList GetMatchingCards(this IEnumerable cards, Func filter)
+ {
+ return cards.Where(card => card?.Data != null && filter.Invoke(card)).ToList();
+ }
+
+ public static int GetMatchingCardsCount(this IEnumerable cards, Func filter)
+ {
+ return cards.Count(card => card?.Data != null && filter.Invoke(card));
+ }
+
+ public static bool IsExistingMatchingCard(this IEnumerable cards, Func filter, int count = 1)
+ {
+ return cards.GetMatchingCardsCount(filter) >= count;
+ }
+
+ public static ClientCard GetShouldBeDisabledBeforeItUseEffectMonster(this IEnumerable cards, bool canBeTarget = true)
+ {
+ return cards.FirstOrDefault(card => card?.Data != null && card.IsMonsterShouldBeDisabledBeforeItUseEffect() && card.IsFaceup() && (!canBeTarget || !card.IsShouldNotBeTarget()));
+ }
+
+ public static IEnumerable> GetCombinations(this IEnumerable elements, int k)
+ {
+ return k == 0 ? new[] { new T[0] } :
+ elements.SelectMany((e, i) =>
+ elements.Skip(i + 1).GetCombinations(k - 1).Select(c => (new[] { e }).Concat(c)));
+ }
+ }
}
\ No newline at end of file
diff --git a/Game/AI/CardExecutor.cs b/ExecutorBase/Game/AI/CardExecutor.cs
similarity index 96%
rename from Game/AI/CardExecutor.cs
rename to ExecutorBase/Game/AI/CardExecutor.cs
index 75509a77..d5ec43dd 100644
--- a/Game/AI/CardExecutor.cs
+++ b/ExecutorBase/Game/AI/CardExecutor.cs
@@ -1,18 +1,18 @@
-using System;
-
-namespace WindBot.Game.AI
-{
- public class CardExecutor
- {
- public int CardId { get; private set; }
- public ExecutorType Type { get; private set; }
- public Func Func { get; private set; }
-
- public CardExecutor(ExecutorType type, int cardId, Func func)
- {
- CardId = cardId;
- Type = type;
- Func = func;
- }
- }
+using System;
+
+namespace WindBot.Game.AI
+{
+ public class CardExecutor
+ {
+ public int CardId { get; private set; }
+ public ExecutorType Type { get; private set; }
+ public Func Func { get; private set; }
+
+ public CardExecutor(ExecutorType type, int cardId, Func func)
+ {
+ CardId = cardId;
+ Type = type;
+ Func = func;
+ }
+ }
}
\ No newline at end of file
diff --git a/Game/AI/CardExtension.cs b/ExecutorBase/Game/AI/CardExtension.cs
similarity index 97%
rename from Game/AI/CardExtension.cs
rename to ExecutorBase/Game/AI/CardExtension.cs
index 8b30394b..3e45daf1 100644
--- a/Game/AI/CardExtension.cs
+++ b/ExecutorBase/Game/AI/CardExtension.cs
@@ -1,80 +1,80 @@
-using System;
-using WindBot.Game.AI.Enums;
-using YGOSharp.OCGWrapper.Enums;
-
-namespace WindBot.Game.AI
-{
- public static class CardExtension
- {
- ///
- /// Is this monster is invincible to battle?
- ///
- public static bool IsMonsterInvincible(this ClientCard card)
- {
- return !card.IsDisabled() && Enum.IsDefined(typeof(InvincibleMonster), card.Id);
- }
-
- ///
- /// Is this monster is dangerous to attack?
- ///
- public static bool IsMonsterDangerous(this ClientCard card)
- {
- return !card.IsDisabled() && Enum.IsDefined(typeof(DangerousMonster), card.Id);
- }
-
- ///
- /// Do this monster prevents activation of opponent's effect monsters in battle?
- ///
- public static bool IsMonsterHasPreventActivationEffectInBattle(this ClientCard card)
- {
- return !card.IsDisabled() && Enum.IsDefined(typeof(PreventActivationEffectInBattle), card.Id);
- }
-
- ///
- /// Is this card shouldn't be tried to be selected as target?
- ///
- public static bool IsShouldNotBeTarget(this ClientCard card)
- {
- return !card.IsDisabled() && !card.HasType(CardType.Normal) && Enum.IsDefined(typeof(ShouldNotBeTarget), card.Id);
- }
-
- ///
- /// Is this card shouldn't be tried to be selected as target of monster?
- ///
- public static bool IsShouldNotBeMonsterTarget(this ClientCard card)
- {
- return !card.IsDisabled() && Enum.IsDefined(typeof(ShouldNotBeMonsterTarget), card.Id);
- }
-
- ///
- /// Is this card shouldn't be tried to be selected as target of spell & trap?
- ///
- public static bool IsShouldNotBeSpellTrapTarget(this ClientCard card)
- {
- return !card.IsDisabled() && Enum.IsDefined(typeof(ShouldNotBeSpellTrapTarget), card.Id);
- }
-
- ///
- /// Is this monster should be disabled (with Breakthrough Skill) before it use effect and release or banish itself?
- ///
- public static bool IsMonsterShouldBeDisabledBeforeItUseEffect(this ClientCard card)
- {
- return !card.IsDisabled() && Enum.IsDefined(typeof(ShouldBeDisabledBeforeItUseEffectMonster), card.Id);
- }
-
- public static bool IsFloodgate(this ClientCard card)
- {
- return Enum.IsDefined(typeof(Floodgate), card.Id);
- }
-
- public static bool IsOneForXyz(this ClientCard card)
- {
- return Enum.IsDefined(typeof(OneForXyz), card.Id);
- }
-
- public static bool IsFusionSpell(this ClientCard card)
- {
- return Enum.IsDefined(typeof(FusionSpell), card.Id);
- }
- }
+using System;
+using WindBot.Game.AI.Enums;
+using YGOSharp.OCGWrapper.Enums;
+
+namespace WindBot.Game.AI
+{
+ public static class CardExtension
+ {
+ ///
+ /// Is this monster is invincible to battle?
+ ///
+ public static bool IsMonsterInvincible(this ClientCard card)
+ {
+ return !card.IsDisabled() && Enum.IsDefined(typeof(InvincibleMonster), card.Id);
+ }
+
+ ///
+ /// Is this monster is dangerous to attack?
+ ///
+ public static bool IsMonsterDangerous(this ClientCard card)
+ {
+ return !card.IsDisabled() && Enum.IsDefined(typeof(DangerousMonster), card.Id);
+ }
+
+ ///
+ /// Do this monster prevents activation of opponent's effect monsters in battle?
+ ///
+ public static bool IsMonsterHasPreventActivationEffectInBattle(this ClientCard card)
+ {
+ return !card.IsDisabled() && Enum.IsDefined(typeof(PreventActivationEffectInBattle), card.Id);
+ }
+
+ ///
+ /// Is this card shouldn't be tried to be selected as target?
+ ///
+ public static bool IsShouldNotBeTarget(this ClientCard card)
+ {
+ return !card.IsDisabled() && !card.HasType(CardType.Normal) && Enum.IsDefined(typeof(ShouldNotBeTarget), card.Id);
+ }
+
+ ///
+ /// Is this card shouldn't be tried to be selected as target of monster?
+ ///
+ public static bool IsShouldNotBeMonsterTarget(this ClientCard card)
+ {
+ return !card.IsDisabled() && Enum.IsDefined(typeof(ShouldNotBeMonsterTarget), card.Id);
+ }
+
+ ///
+ /// Is this card shouldn't be tried to be selected as target of spell & trap?
+ ///
+ public static bool IsShouldNotBeSpellTrapTarget(this ClientCard card)
+ {
+ return !card.IsDisabled() && Enum.IsDefined(typeof(ShouldNotBeSpellTrapTarget), card.Id);
+ }
+
+ ///
+ /// Is this monster should be disabled (with Breakthrough Skill) before it use effect and release or banish itself?
+ ///
+ public static bool IsMonsterShouldBeDisabledBeforeItUseEffect(this ClientCard card)
+ {
+ return !card.IsDisabled() && Enum.IsDefined(typeof(ShouldBeDisabledBeforeItUseEffectMonster), card.Id);
+ }
+
+ public static bool IsFloodgate(this ClientCard card)
+ {
+ return Enum.IsDefined(typeof(Floodgate), card.Id);
+ }
+
+ public static bool IsOneForXyz(this ClientCard card)
+ {
+ return Enum.IsDefined(typeof(OneForXyz), card.Id);
+ }
+
+ public static bool IsFusionSpell(this ClientCard card)
+ {
+ return Enum.IsDefined(typeof(FusionSpell), card.Id);
+ }
+ }
}
\ No newline at end of file
diff --git a/Game/AI/CardSelector.cs b/ExecutorBase/Game/AI/CardSelector.cs
similarity index 96%
rename from Game/AI/CardSelector.cs
rename to ExecutorBase/Game/AI/CardSelector.cs
index 5a0cf2ba..fda0bb55 100644
--- a/Game/AI/CardSelector.cs
+++ b/ExecutorBase/Game/AI/CardSelector.cs
@@ -1,104 +1,104 @@
-using System.Collections.Generic;
-using YGOSharp.OCGWrapper.Enums;
-
-namespace WindBot.Game.AI
-{
- public class CardSelector
- {
- private enum SelectType
- {
- Card,
- Cards,
- Id,
- Ids,
- Location
- }
-
- private SelectType _type;
- private ClientCard _card;
- private IList _cards;
- private int _id;
- private IList _ids;
- private CardLocation _location;
-
- public CardSelector(ClientCard card)
- {
- _type = SelectType.Card;
- _card = card;
- }
-
- public CardSelector(IList cards)
- {
- _type = SelectType.Cards;
- _cards = cards;
- }
-
- public CardSelector(int cardId)
- {
- _type = SelectType.Id;
- _id = cardId;
- }
-
- public CardSelector(IList ids)
- {
- _type = SelectType.Ids;
- _ids = ids;
- }
-
- public CardSelector(CardLocation location)
- {
- _type = SelectType.Location;
- _location = location;
- }
-
- public IList Select(IList cards, int min, int max)
- {
- IList result = new List();
-
- switch (_type)
- {
- case SelectType.Card:
- if (cards.Contains(_card))
- result.Add(_card);
- break;
- case SelectType.Cards:
- foreach (ClientCard card in _cards)
- if (cards.Contains(card) && !result.Contains(card))
- result.Add(card);
- break;
- case SelectType.Id:
- foreach (ClientCard card in cards)
- if (card.IsCode(_id))
- result.Add(card);
- break;
- case SelectType.Ids:
- foreach (int id in _ids)
- foreach (ClientCard card in cards)
- if (card.IsCode(id) && !result.Contains(card))
- result.Add(card);
- break;
- case SelectType.Location:
- foreach (ClientCard card in cards)
- if (card.Location == _location)
- result.Add(card);
- break;
- }
-
- if (result.Count < min)
- {
- foreach (ClientCard card in cards)
- {
- if (!result.Contains(card))
- result.Add(card);
- if (result.Count >= min)
- break;
- }
- }
-
- while (result.Count > max)
- result.RemoveAt(result.Count - 1);
-
- return result;
- }
- }
+using System.Collections.Generic;
+using YGOSharp.OCGWrapper.Enums;
+
+namespace WindBot.Game.AI
+{
+ public class CardSelector
+ {
+ private enum SelectType
+ {
+ Card,
+ Cards,
+ Id,
+ Ids,
+ Location
+ }
+
+ private SelectType _type;
+ private ClientCard _card;
+ private IList _cards;
+ private int _id;
+ private IList _ids;
+ private CardLocation _location;
+
+ public CardSelector(ClientCard card)
+ {
+ _type = SelectType.Card;
+ _card = card;
+ }
+
+ public CardSelector(IList cards)
+ {
+ _type = SelectType.Cards;
+ _cards = cards;
+ }
+
+ public CardSelector(int cardId)
+ {
+ _type = SelectType.Id;
+ _id = cardId;
+ }
+
+ public CardSelector(IList ids)
+ {
+ _type = SelectType.Ids;
+ _ids = ids;
+ }
+
+ public CardSelector(CardLocation location)
+ {
+ _type = SelectType.Location;
+ _location = location;
+ }
+
+ public IList Select(IList cards, int min, int max)
+ {
+ IList result = new List();
+
+ switch (_type)
+ {
+ case SelectType.Card:
+ if (cards.Contains(_card))
+ result.Add(_card);
+ break;
+ case SelectType.Cards:
+ foreach (ClientCard card in _cards)
+ if (cards.Contains(card) && !result.Contains(card))
+ result.Add(card);
+ break;
+ case SelectType.Id:
+ foreach (ClientCard card in cards)
+ if (card.IsCode(_id))
+ result.Add(card);
+ break;
+ case SelectType.Ids:
+ foreach (int id in _ids)
+ foreach (ClientCard card in cards)
+ if (card.IsCode(id) && !result.Contains(card))
+ result.Add(card);
+ break;
+ case SelectType.Location:
+ foreach (ClientCard card in cards)
+ if (card.Location == _location)
+ result.Add(card);
+ break;
+ }
+
+ if (result.Count < min)
+ {
+ foreach (ClientCard card in cards)
+ {
+ if (!result.Contains(card))
+ result.Add(card);
+ if (result.Count >= min)
+ break;
+ }
+ }
+
+ while (result.Count > max)
+ result.RemoveAt(result.Count - 1);
+
+ return result;
+ }
+ }
}
\ No newline at end of file
diff --git a/Game/AI/DeckAttribute.cs b/ExecutorBase/Game/AI/DeckAttribute.cs
similarity index 96%
rename from Game/AI/DeckAttribute.cs
rename to ExecutorBase/Game/AI/DeckAttribute.cs
index 49bae161..89a87a9c 100644
--- a/Game/AI/DeckAttribute.cs
+++ b/ExecutorBase/Game/AI/DeckAttribute.cs
@@ -1,22 +1,22 @@
-using System;
-
-namespace WindBot.Game.AI
-{
- [AttributeUsage(AttributeTargets.Class)]
- public class DeckAttribute : Attribute
- {
- public string Name { get; private set; }
- public string File { get; private set; }
- public string Level { get; private set; }
-
- public DeckAttribute(string name, string file = null, string level = "Normal")
- {
- if (String.IsNullOrEmpty(file))
- file = name;
-
- Name = name;
- File = file;
- Level = level;
- }
- }
-}
+using System;
+
+namespace WindBot.Game.AI
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ public class DeckAttribute : Attribute
+ {
+ public string Name { get; private set; }
+ public string File { get; private set; }
+ public string Level { get; private set; }
+
+ public DeckAttribute(string name, string file = null, string level = "Normal")
+ {
+ if (String.IsNullOrEmpty(file))
+ file = name;
+
+ Name = name;
+ File = file;
+ Level = level;
+ }
+ }
+}
diff --git a/Game/AI/DefaultExecutor.cs b/ExecutorBase/Game/AI/DefaultExecutor.cs
similarity index 97%
rename from Game/AI/DefaultExecutor.cs
rename to ExecutorBase/Game/AI/DefaultExecutor.cs
index 3eb0b663..27580a47 100644
--- a/Game/AI/DefaultExecutor.cs
+++ b/ExecutorBase/Game/AI/DefaultExecutor.cs
@@ -1,1101 +1,1101 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using YGOSharp.OCGWrapper.Enums;
-using WindBot;
-using WindBot.Game;
-using WindBot.Game.AI;
-
-namespace WindBot.Game.AI
-{
- public abstract class DefaultExecutor : Executor
- {
- protected class _CardId
- {
- public const int JizukirutheStarDestroyingKaiju = 63941210;
- public const int ThunderKingtheLightningstrikeKaiju = 48770333;
- public const int DogorantheMadFlameKaiju = 93332803;
- public const int RadiantheMultidimensionalKaiju = 28674152;
- public const int GadarlatheMysteryDustKaiju = 36956512;
- public const int KumongoustheStickyStringKaiju = 29726552;
- public const int GamecieltheSeaTurtleKaiju = 55063751;
- public const int SuperAntiKaijuWarMachineMechaDogoran = 84769941;
-
- public const int UltimateConductorTytanno = 18940556;
- public const int ElShaddollConstruct = 20366274;
- public const int AllyOfJusticeCatastor = 26593852;
-
- public const int DupeFrog = 46239604;
- public const int MaraudingCaptain = 2460565;
-
- public const int BlackRoseDragon = 73580471;
- public const int JudgmentDragon = 57774843;
- public const int TopologicTrisbaena = 72529749;
- public const int EvilswarmExcitonKnight = 46772449;
- public const int HarpiesFeatherDuster = 18144506;
- public const int DarkMagicAttack = 2314238;
- public const int MysticalSpaceTyphoon = 5318639;
- public const int CosmicCyclone = 8267140;
- public const int ChickenGame = 67616300;
-
- public const int SantaClaws = 46565218;
-
- public const int CastelTheSkyblasterMusketeer = 82633039;
- public const int CrystalWingSynchroDragon = 50954680;
- public const int NumberS39UtopiaTheLightning = 56832966;
- public const int Number39Utopia = 84013237;
- public const int UltimayaTzolkin = 1686814;
- public const int MekkKnightCrusadiaAstram = 21887175;
- public const int HamonLordofStrikingThunder = 32491822;
-
- public const int MoonMirrorShield = 19508728;
- public const int PhantomKnightsFogBlade = 25542642;
-
- public const int VampireFraeulein = 6039967;
- public const int InjectionFairyLily = 79575620;
-
- public const int BlueEyesChaosMAXDragon = 55410871;
-
- public const int AshBlossom = 14558127;
- public const int MaxxC = 23434538;
- public const int LockBird = 94145021;
- public const int GhostOgreAndSnowRabbit = 59438930;
- public const int GhostBelle = 73642296;
- public const int EffectVeiler = 63845230;
- public const int ArtifactLancea = 34267821;
-
- public const int CalledByTheGrave = 24224830;
- public const int InfiniteImpermanence = 10045474;
- public const int GalaxySoldier = 46659709;
- public const int MacroCosmos = 30241314;
- public const int UpstartGoblin = 70368879;
- public const int CyberEmergency = 60600126;
-
- public const int EaterOfMillions = 63845230;
-
- public const int InvokedPurgatrio = 12307878;
- public const int ChaosAncientGearGiant = 51788412;
- public const int UltimateAncientGearGolem = 12652643;
-
- public const int RedDragonArchfiend = 70902743;
-
- public const int ImperialOrder = 61740673;
- public const int NaturiaBeast = 33198837;
- public const int AntiSpellFragrance = 58921041;
- }
-
- int HonestEffectCount = 0;
-
- protected DefaultExecutor(GameAI ai, Duel duel)
- : base(ai, duel)
- {
- AddExecutor(ExecutorType.Activate, _CardId.ChickenGame, DefaultChickenGame);
- AddExecutor(ExecutorType.Activate, _CardId.SantaClaws);
- }
-
- ///
- /// Decide which card should the attacker attack.
- ///
- /// Card that attack.
- /// Cards that defend.
- /// BattlePhaseAction including the target, or null (in this situation, GameAI will check the next attacker)
- public override BattlePhaseAction OnSelectAttackTarget(ClientCard attacker, IList defenders)
- {
- foreach (ClientCard defender in defenders)
- {
- attacker.RealPower = attacker.Attack;
- defender.RealPower = defender.GetDefensePower();
- if (!OnPreBattleBetween(attacker, defender))
- continue;
-
- if (attacker.RealPower > defender.RealPower || (attacker.RealPower >= defender.RealPower && attacker.IsLastAttacker && defender.IsAttack()))
- return AI.Attack(attacker, defender);
- }
-
- if (attacker.CanDirectAttack)
- return AI.Attack(attacker, null);
-
- return null;
- }
-
- ///
- /// Decide whether to declare attack between attacker and defender.
- /// Can be overrided to update the RealPower of attacker for cards like Honest.
- ///
- /// Card that attack.
- /// Card that defend.
- /// false if the attack shouldn't be done.
- public override bool OnPreBattleBetween(ClientCard attacker, ClientCard defender)
- {
- if (attacker.RealPower <= 0)
- return false;
-
- if (!attacker.IsMonsterHasPreventActivationEffectInBattle())
- {
- if (defender.IsMonsterInvincible() && defender.IsDefense())
- return false;
-
- if (defender.IsMonsterDangerous())
- {
- bool canIgnoreIt = !attacker.IsDisabled() && (
- attacker.IsCode(_CardId.UltimateConductorTytanno) && defender.IsDefense() ||
- attacker.IsCode(_CardId.ElShaddollConstruct) && defender.IsSpecialSummoned ||
- attacker.IsCode(_CardId.AllyOfJusticeCatastor) && !defender.HasAttribute(CardAttribute.Dark));
- if (!canIgnoreIt)
- return false;
- }
-
- foreach (ClientCard equip in defender.EquipCards)
- {
- if (equip.IsCode(_CardId.MoonMirrorShield) && !equip.IsDisabled())
- {
- return false;
- }
- }
-
- if (!defender.IsDisabled())
- {
- if (defender.IsCode(_CardId.MekkKnightCrusadiaAstram) && defender.IsAttack() && attacker.IsSpecialSummoned)
- return false;
-
- if (defender.IsCode(_CardId.CrystalWingSynchroDragon) && defender.IsAttack() && attacker.Level >= 5)
- return false;
-
- if (defender.IsCode(_CardId.AllyOfJusticeCatastor) && !attacker.HasAttribute(CardAttribute.Dark))
- return false;
-
- if (defender.IsCode(_CardId.NumberS39UtopiaTheLightning) && defender.IsAttack() && defender.HasXyzMaterial(2, _CardId.Number39Utopia))
- defender.RealPower = 5000;
-
- if (defender.IsCode(_CardId.VampireFraeulein))
- defender.RealPower += (Enemy.LifePoints > 3000) ? 3000 : (Enemy.LifePoints - 100);
-
- if (defender.IsCode(_CardId.InjectionFairyLily) && Enemy.LifePoints > 2000)
- defender.RealPower += 3000;
- }
- }
-
- if (!defender.IsMonsterHasPreventActivationEffectInBattle())
- {
- if (attacker.IsCode(_CardId.NumberS39UtopiaTheLightning) && !attacker.IsDisabled() && attacker.HasXyzMaterial(2, _CardId.Number39Utopia))
- attacker.RealPower = 5000;
-
- foreach (ClientCard equip in attacker.EquipCards)
- {
- if (equip.IsCode(_CardId.MoonMirrorShield) && !equip.IsDisabled())
- {
- attacker.RealPower = defender.RealPower + 100;
- }
- }
- }
-
- if (Enemy.HasInMonstersZone(_CardId.MekkKnightCrusadiaAstram, true) && !(defender).IsCode(_CardId.MekkKnightCrusadiaAstram))
- return false;
-
- if (Enemy.HasInMonstersZone(_CardId.DupeFrog, true) && !(defender).IsCode(_CardId.DupeFrog))
- return false;
-
- if (Enemy.HasInMonstersZone(_CardId.MaraudingCaptain, true) && !defender.IsCode(_CardId.MaraudingCaptain) && defender.Race == (int)CardRace.Warrior)
- return false;
-
- if (defender.IsCode(_CardId.UltimayaTzolkin) && !defender.IsDisabled() && Enemy.GetMonsters().Any(monster => !monster.Equals(defender) && monster.HasType(CardType.Synchro)))
- 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;
-
- return true;
- }
-
- ///
- /// Called when the AI has to select a card position.
- ///
- /// Id of the card to position on the field.
- /// List of available positions.
- /// Selected position, or 0 if no position is set for this card.
- public override CardPosition OnSelectPosition(int cardId, IList positions)
- {
- YGOSharp.OCGWrapper.NamedCard cardData = YGOSharp.OCGWrapper.NamedCard.Get(cardId);
- if (cardData != null)
- {
- if (cardData.Attack == 0)
- return CardPosition.FaceUpDefence;
- }
- return 0;
- }
-
- public override bool OnSelectBattleReplay()
- {
- if (Bot.BattlingMonster == null)
- return false;
- List defenders = new List(Duel.Fields[1].GetMonsters());
- defenders.Sort(CardContainer.CompareDefensePower);
- defenders.Reverse();
- BattlePhaseAction result = OnSelectAttackTarget(Bot.BattlingMonster, defenders);
- if (result != null && result.Action == BattlePhaseAction.BattleAction.Attack)
- {
- return true;
- }
- return false;
- }
-
- public override void OnNewTurn()
- {
- HonestEffectCount = 0;
- }
-
- ///
- /// Destroy face-down cards first, in our turn.
- ///
- protected bool DefaultMysticalSpaceTyphoon()
- {
- if (Duel.CurrentChain.Any(card => card.IsCode(_CardId.MysticalSpaceTyphoon)))
- {
- return false;
- }
-
- List spells = Enemy.GetSpells();
- if (spells.Count == 0)
- return false;
-
- ClientCard selected = Enemy.SpellZone.GetFloodgate();
-
- if (selected == null)
- {
- if (Duel.Player == 0)
- selected = spells.FirstOrDefault(card => card.IsFacedown());
- if (Duel.Player == 1)
- selected = spells.FirstOrDefault(card => card.HasType(CardType.Continuous) || card.HasType(CardType.Equip) || card.HasType(CardType.Field));
- }
-
- if (selected == null)
- return false;
- AI.SelectCard(selected);
- return true;
- }
-
- ///
- /// Destroy face-down cards first, in our turn.
- ///
- protected bool DefaultCosmicCyclone()
- {
- foreach (ClientCard card in Duel.CurrentChain)
- if (card.IsCode(_CardId.CosmicCyclone))
- return false;
- return (Bot.LifePoints > 1000) && DefaultMysticalSpaceTyphoon();
- }
-
- ///
- /// Activate if avail.
- ///
- protected bool DefaultGalaxyCyclone()
- {
- List spells = Enemy.GetSpells();
- if (spells.Count == 0)
- return false;
-
- ClientCard selected = null;
-
- if (Card.Location == CardLocation.Grave)
- {
- selected = Util.GetBestEnemySpell(true);
- }
- else
- {
- selected = spells.FirstOrDefault(card => card.IsFacedown());
- }
-
- if (selected == null)
- return false;
-
- AI.SelectCard(selected);
- return true;
- }
-
- ///
- /// Set the highest ATK level 4+ effect enemy monster.
- ///
- protected bool DefaultBookOfMoon()
- {
- if (Util.IsAllEnemyBetter(true))
- {
- ClientCard monster = Enemy.GetMonsters().GetHighestAttackMonster(true);
- if (monster != null && monster.HasType(CardType.Effect) && !monster.HasType(CardType.Link) && (monster.HasType(CardType.Xyz) || monster.Level > 4))
- {
- AI.SelectCard(monster);
- return true;
- }
- }
- return false;
- }
-
- ///
- /// Return problematic monster, and if this card become target, return any enemy monster.
- ///
- protected bool DefaultCompulsoryEvacuationDevice()
- {
- ClientCard target = Util.GetProblematicEnemyMonster(0, true);
- if (target != null)
- {
- AI.SelectCard(target);
- return true;
- }
- if (Util.IsChainTarget(Card))
- {
- ClientCard monster = Util.GetBestEnemyMonster(false, true);
- if (monster != null)
- {
- AI.SelectCard(monster);
- return true;
- }
- }
- return false;
- }
-
- ///
- /// Revive the best monster when we don't have better one in field.
- ///
- protected bool DefaultCallOfTheHaunted()
- {
- if (!Util.IsAllEnemyBetter(true))
- return false;
- ClientCard selected = Bot.Graveyard.GetMatchingCards(card => card.IsCanRevive()).OrderByDescending(card => card.Attack).FirstOrDefault();
- AI.SelectCard(selected);
- return true;
- }
-
- ///
- /// Default Scapegoat effect
- ///
- protected bool DefaultScapegoat()
- {
- if (DefaultSpellWillBeNegated()) return false;
- if (Duel.Player == 0) return false;
- if (Duel.Phase == DuelPhase.End) return true;
- if (DefaultOnBecomeTarget()) return true;
- if (Duel.Phase > DuelPhase.Main1 && Duel.Phase < DuelPhase.Main2)
- {
- if (Enemy.HasInMonstersZone(new[]
- {
- _CardId.UltimateConductorTytanno,
- _CardId.InvokedPurgatrio,
- _CardId.ChaosAncientGearGiant,
- _CardId.UltimateAncientGearGolem,
- _CardId.RedDragonArchfiend
- }, true)) return false;
- if (Util.GetTotalAttackingMonsterAttack(1) >= Bot.LifePoints) return true;
- }
- return false;
- }
- ///
- /// Always active in opponent's turn.
- ///
- protected bool DefaultMaxxC()
- {
- return Duel.Player == 1;
- }
- ///
- /// Always disable opponent's effect except some cards like UpstartGoblin
- ///
- protected bool DefaultAshBlossomAndJoyousSpring()
- {
- int[] ignoreList = {
- _CardId.MacroCosmos,
- _CardId.UpstartGoblin,
- _CardId.CyberEmergency
- };
- if (Util.GetLastChainCard().IsCode(ignoreList))
- return false;
- if (Util.GetLastChainCard().HasSetcode(0x11e) && Util.GetLastChainCard().Location == CardLocation.Hand) // Danger! archtype hand effect
- return false;
- return Duel.LastChainPlayer == 1;
- }
- ///
- /// Always activate unless the activating card is disabled
- ///
- protected bool DefaultGhostOgreAndSnowRabbit()
- {
- if (Util.GetLastChainCard() != null && Util.GetLastChainCard().IsDisabled())
- return false;
- return DefaultTrap();
- }
- ///
- /// Always disable opponent's effect
- ///
- protected bool DefaultGhostBelleAndHauntedMansion()
- {
- return DefaultTrap();
- }
- ///
- /// Same as DefaultBreakthroughSkill
- ///
- protected bool DefaultEffectVeiler()
- {
- if (Util.GetLastChainCard() != null && Util.GetLastChainCard().IsCode(_CardId.GalaxySoldier) && Enemy.Hand.Count >= 3) return false;
- if (Util.ChainContainsCard(_CardId.EffectVeiler))
- return false;
- return DefaultBreakthroughSkill();
- }
- ///
- /// Chain common hand traps
- ///
- protected bool DefaultCalledByTheGrave()
- {
- int[] targetList =
- {
- _CardId.MaxxC,
- _CardId.LockBird,
- _CardId.GhostOgreAndSnowRabbit,
- _CardId.AshBlossom,
- _CardId.GhostBelle,
- _CardId.EffectVeiler,
- _CardId.ArtifactLancea
- };
- if (Duel.LastChainPlayer == 1)
- {
- foreach (int id in targetList)
- {
- if (Util.GetLastChainCard().IsCode(id))
- {
- AI.SelectCard(id);
- return UniqueFaceupSpell();
- }
- }
- }
- return false;
- }
- ///
- /// Default InfiniteImpermanence effect
- ///
- protected bool DefaultInfiniteImpermanence()
- {
- // TODO: disable s & t
- if (!DefaultUniqueTrap())
- return false;
- return DefaultDisableMonster();
- }
- ///
- /// Chain the enemy monster, or disable monster like Rescue Rabbit.
- ///
- protected bool DefaultBreakthroughSkill()
- {
- if (!DefaultUniqueTrap())
- return false;
- return DefaultDisableMonster();
- }
- ///
- /// Chain the enemy monster, or disable monster like Rescue Rabbit.
- ///
- protected bool DefaultDisableMonster()
- {
- if (Duel.Player == 1)
- {
- ClientCard target = Enemy.MonsterZone.GetShouldBeDisabledBeforeItUseEffectMonster();
- if (target != null)
- {
- AI.SelectCard(target);
- return true;
- }
- }
-
- ClientCard LastChainCard = Util.GetLastChainCard();
-
- if (LastChainCard != null && LastChainCard.Controller == 1 && LastChainCard.Location == CardLocation.MonsterZone &&
- !LastChainCard.IsDisabled() && !LastChainCard.IsShouldNotBeTarget() && !LastChainCard.IsShouldNotBeSpellTrapTarget())
- {
- AI.SelectCard(LastChainCard);
- return true;
- }
-
- if (Bot.BattlingMonster != null && Enemy.BattlingMonster != null)
- {
- if (!Enemy.BattlingMonster.IsDisabled() && Enemy.BattlingMonster.IsCode(_CardId.EaterOfMillions))
- {
- AI.SelectCard(Enemy.BattlingMonster);
- return true;
- }
- }
-
- if (Duel.Phase == DuelPhase.BattleStart && Duel.Player == 1 &&
- Enemy.HasInMonstersZone(_CardId.NumberS39UtopiaTheLightning, true))
- {
- AI.SelectCard(_CardId.NumberS39UtopiaTheLightning);
- return true;
- }
-
- return false;
- }
-
- ///
- /// Activate only except this card is the target or we summon monsters.
- ///
- protected bool DefaultSolemnJudgment()
- {
- return !Util.IsChainTargetOnly(Card) && !(Duel.Player == 0 && Duel.LastChainPlayer == -1) && DefaultTrap();
- }
-
- ///
- /// Activate only except we summon monsters.
- ///
- protected bool DefaultSolemnWarning()
- {
- return (Bot.LifePoints > 2000) && !(Duel.Player == 0 && Duel.LastChainPlayer == -1) && DefaultTrap();
- }
-
- ///
- /// Activate only except we summon monsters.
- ///
- protected bool DefaultSolemnStrike()
- {
- return (Bot.LifePoints > 1500) && !(Duel.Player == 0 && Duel.LastChainPlayer == -1) && DefaultTrap();
- }
-
- ///
- /// Activate when all enemy monsters have better ATK.
- ///
- protected bool DefaultTorrentialTribute()
- {
- return !Util.HasChainedTrap(0) && Util.IsAllEnemyBetter(true);
- }
-
- ///
- /// Activate enemy have more S&T.
- ///
- protected bool DefaultHeavyStorm()
- {
- return Bot.GetSpellCount() < Enemy.GetSpellCount();
- }
-
- ///
- /// Activate before other winds, if enemy have more than 2 S&T.
- ///
- protected bool DefaultHarpiesFeatherDusterFirst()
- {
- return Enemy.GetSpellCount() >= 2;
- }
-
- ///
- /// Activate when one enemy monsters have better ATK.
- ///
- protected bool DefaultHammerShot()
- {
- return Util.IsOneEnemyBetter(true);
- }
-
- ///
- /// Activate when one enemy monsters have better ATK or DEF.
- ///
- protected bool DefaultDarkHole()
- {
- return Util.IsOneEnemyBetter();
- }
-
- ///
- /// Activate when one enemy monsters have better ATK or DEF.
- ///
- protected bool DefaultRaigeki()
- {
- return Util.IsOneEnemyBetter();
- }
-
- ///
- /// Activate when one enemy monsters have better ATK or DEF.
- ///
- protected bool DefaultSmashingGround()
- {
- return Util.IsOneEnemyBetter();
- }
-
- ///
- /// Activate when we have more than 15 cards in deck.
- ///
- protected bool DefaultPotOfDesires()
- {
- return Bot.Deck.Count > 15;
- }
-
- ///
- /// Set traps only and avoid block the activation of other cards.
- ///
- protected bool DefaultSpellSet()
- {
- return (Card.IsTrap() || Card.HasType(CardType.QuickPlay)) && Bot.GetSpellCountWithoutField() < 4;
- }
-
- ///
- /// Summon with tributes ATK lower.
- ///
- protected bool DefaultTributeSummon()
- {
- if (!UniqueFaceupMonster())
- return false;
- int tributecount = (int)Math.Ceiling((Card.Level - 4.0d) / 2.0d);
- for (int j = 0; j < 7; ++j)
- {
- ClientCard tributeCard = Bot.MonsterZone[j];
- if (tributeCard == null) continue;
- if (tributeCard.GetDefensePower() < Card.Attack)
- tributecount--;
- }
- return tributecount <= 0;
- }
-
- ///
- /// Activate when we have no field.
- ///
- protected bool DefaultField()
- {
- return Bot.SpellZone[5] == null;
- }
-
- ///
- /// Turn if all enemy is better.
- ///
- protected bool DefaultMonsterRepos()
- {
- if (Card.IsFaceup() && Card.IsDefense() && Card.Attack == 0)
- return false;
-
- if (Enemy.HasInMonstersZone(_CardId.BlueEyesChaosMAXDragon, true) &&
- Card.IsAttack() && (4000 - Card.Defense) * 2 > (4000 - Card.Attack))
- return false;
- if (Enemy.HasInMonstersZone(_CardId.BlueEyesChaosMAXDragon, true) &&
- Card.IsDefense() && Card.IsFaceup() &&
- (4000 - Card.Defense) * 2 > (4000 - Card.Attack))
- return true;
-
- bool enemyBetter = Util.IsAllEnemyBetter(true);
- if (Card.IsAttack() && enemyBetter)
- return true;
- if (Card.IsDefense() && !enemyBetter && Card.Attack >= Card.Defense)
- return true;
-
- return false;
- }
-
- ///
- /// If spell will be negated
- ///
- protected bool DefaultSpellWillBeNegated()
- {
- return Bot.HasInSpellZone(_CardId.ImperialOrder, true, true) || Enemy.HasInSpellZone(_CardId.ImperialOrder, true) || Enemy.HasInMonstersZone(_CardId.NaturiaBeast, true);
- }
-
- ///
- /// If spell must set first to activate
- ///
- protected bool DefaultSpellMustSetFirst()
- {
- ClientCard card = null;
- foreach (ClientCard check in Bot.GetSpells())
- {
- if (check.IsCode(_CardId.AntiSpellFragrance) && !check.IsDisabled())
- card = check;
- }
- if (card != null && card.IsFaceup())
- return true;
- return Bot.HasInSpellZone(_CardId.AntiSpellFragrance, true, true) || Enemy.HasInSpellZone(_CardId.AntiSpellFragrance, true);
- }
-
- ///
- /// if spell/trap is the target or enermy activate HarpiesFeatherDuster
- ///
- protected bool DefaultOnBecomeTarget()
- {
- if (Util.IsChainTarget(Card)) return true;
- int[] destroyAllList =
- {
- _CardId.EvilswarmExcitonKnight,
- _CardId.BlackRoseDragon,
- _CardId.JudgmentDragon,
- _CardId.TopologicTrisbaena
- };
- int[] destroyAllOpponentList =
- {
- _CardId.HarpiesFeatherDuster,
- _CardId.DarkMagicAttack
- };
-
- if (Util.ChainContainsCard(destroyAllList)) return true;
- if (Enemy.HasInSpellZone(destroyAllOpponentList, true)) return true;
- // TODO: ChainContainsCard(id, player)
- return false;
- }
- ///
- /// Chain enemy activation or summon.
- ///
- protected bool DefaultTrap()
- {
- return (Duel.LastChainPlayer == -1 && Duel.LastSummonPlayer != 0) || Duel.LastChainPlayer == 1;
- }
-
- ///
- /// Activate when avail and no other our trap card in this chain or face-up.
- ///
- protected bool DefaultUniqueTrap()
- {
- if (Util.HasChainedTrap(0))
- return false;
-
- return UniqueFaceupSpell();
- }
-
- ///
- /// Check no other our spell or trap card with same name face-up.
- ///
- protected bool UniqueFaceupSpell()
- {
- return !Bot.GetSpells().Any(card => card.IsCode(Card.Id) && card.IsFaceup());
- }
-
- ///
- /// Check no other our monster card with same name face-up.
- ///
- protected bool UniqueFaceupMonster()
- {
- return !Bot.GetMonsters().Any(card => card.IsCode(Card.Id) && card.IsFaceup());
- }
-
- ///
- /// Dumb way to avoid the bot chain in mess.
- ///
- protected bool DefaultDontChainMyself()
- {
- if (Executors.Any(exec => exec.Type == Type && exec.CardId == Card.Id))
- return false;
- return Duel.LastChainPlayer != 0;
- }
-
- ///
- /// Draw when we have lower LP, or destroy it. Can be overrided.
- ///
- protected bool DefaultChickenGame()
- {
- if (Executors.Count(exec => exec.Type == Type && exec.CardId == Card.Id) > 1)
- return false;
- if (Bot.LifePoints <= 1000)
- return false;
- if (Bot.LifePoints <= Enemy.LifePoints && ActivateDescription == Util.GetStringId(_CardId.ChickenGame, 0))
- return true;
- if (Bot.LifePoints > Enemy.LifePoints && ActivateDescription == Util.GetStringId(_CardId.ChickenGame, 1))
- return true;
- return false;
- }
-
- ///
- /// Draw when we have Dark monster in hand,and banish random one. Can be overrided.
- ///
- protected bool DefaultAllureofDarkness()
- {
- ClientCard target = Bot.Hand.FirstOrDefault(card => card.HasAttribute(CardAttribute.Dark));
- return target != null;
- }
-
- ///
- /// Clever enough.
- ///
- protected bool DefaultDimensionalBarrier()
- {
- const int RITUAL = 0;
- const int FUSION = 1;
- const int SYNCHRO = 2;
- const int XYZ = 3;
- const int PENDULUM = 4;
- if (Duel.Player != 0)
- {
- List monsters = Enemy.GetMonsters();
- int[] levels = new int[13];
- bool tuner = false;
- 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))
- {
- nontuner = true;
- levels[monster.Level] = levels[monster.Level] + 1;
- }
-
- if (monster.IsOneForXyz())
- {
- AI.SelectOption(XYZ);
- return true;
- }
- }
- if (tuner && nontuner)
- {
- AI.SelectOption(SYNCHRO);
- return true;
- }
- for (int i=1; i<=12; i++)
- {
- if (levels[i]>1)
- {
- AI.SelectOption(XYZ);
- return true;
- }
- }
- ClientCard l = Enemy.SpellZone[6];
- ClientCard r = Enemy.SpellZone[7];
- if (l != null && r != null && l.LScale != r.RScale)
- {
- AI.SelectOption(PENDULUM);
- return true;
- }
- }
- ClientCard lastchaincard = Util.GetLastChainCard();
- if (Duel.LastChainPlayer == 1 && lastchaincard != null && !lastchaincard.IsDisabled())
- {
- if (lastchaincard.HasType(CardType.Ritual))
- {
- AI.SelectOption(RITUAL);
- return true;
- }
- if (lastchaincard.HasType(CardType.Fusion))
- {
- AI.SelectOption(FUSION);
- return true;
- }
- if (lastchaincard.HasType(CardType.Synchro))
- {
- AI.SelectOption(SYNCHRO);
- return true;
- }
- if (lastchaincard.HasType(CardType.Xyz))
- {
- AI.SelectOption(XYZ);
- return true;
- }
- if (lastchaincard.IsFusionSpell())
- {
- AI.SelectOption(FUSION);
- return true;
- }
- }
- if (Util.IsChainTarget(Card))
- {
- AI.SelectOption(XYZ);
- return true;
- }
- return false;
- }
-
- ///
- /// Clever enough
- ///
- protected bool DefaultInterruptedKaijuSlumber()
- {
- if (Card.Location == CardLocation.Grave)
- {
- AI.SelectCard(
- _CardId.GamecieltheSeaTurtleKaiju,
- _CardId.KumongoustheStickyStringKaiju,
- _CardId.GadarlatheMysteryDustKaiju,
- _CardId.RadiantheMultidimensionalKaiju,
- _CardId.DogorantheMadFlameKaiju,
- _CardId.ThunderKingtheLightningstrikeKaiju,
- _CardId.JizukirutheStarDestroyingKaiju
- );
- return true;
- }
-
- if (DefaultDarkHole())
- {
- AI.SelectCard(
- _CardId.JizukirutheStarDestroyingKaiju,
- _CardId.ThunderKingtheLightningstrikeKaiju,
- _CardId.DogorantheMadFlameKaiju,
- _CardId.RadiantheMultidimensionalKaiju,
- _CardId.GadarlatheMysteryDustKaiju,
- _CardId.KumongoustheStickyStringKaiju,
- _CardId.GamecieltheSeaTurtleKaiju
- );
- AI.SelectNextCard(
- _CardId.SuperAntiKaijuWarMachineMechaDogoran,
- _CardId.GamecieltheSeaTurtleKaiju,
- _CardId.KumongoustheStickyStringKaiju,
- _CardId.GadarlatheMysteryDustKaiju,
- _CardId.RadiantheMultidimensionalKaiju,
- _CardId.DogorantheMadFlameKaiju,
- _CardId.ThunderKingtheLightningstrikeKaiju
- );
- return true;
- }
-
- return false;
- }
-
- ///
- /// Clever enough.
- ///
- protected bool DefaultKaijuSpsummon()
- {
- IList kaijus = new[] {
- _CardId.JizukirutheStarDestroyingKaiju,
- _CardId.GadarlatheMysteryDustKaiju,
- _CardId.GamecieltheSeaTurtleKaiju,
- _CardId.RadiantheMultidimensionalKaiju,
- _CardId.KumongoustheStickyStringKaiju,
- _CardId.ThunderKingtheLightningstrikeKaiju,
- _CardId.DogorantheMadFlameKaiju,
- _CardId.SuperAntiKaijuWarMachineMechaDogoran
- };
- foreach (ClientCard monster in Enemy.GetMonsters())
- {
- if (monster.IsCode(kaijus))
- return Card.GetDefensePower() > monster.GetDefensePower();
- }
- ClientCard card = Enemy.MonsterZone.GetFloodgate();
- if (card != null)
- {
- AI.SelectCard(card);
- return true;
- }
- card = Enemy.MonsterZone.GetDangerousMonster();
- if (card != null)
- {
- AI.SelectCard(card);
- return true;
- }
- card = Util.GetOneEnemyBetterThanValue(Card.GetDefensePower());
- if (card != null)
- {
- AI.SelectCard(card);
- return true;
- }
- return false;
- }
-
- ///
- /// Summon when we don't have monster attack higher than enemy's.
- ///
- protected bool DefaultNumberS39UtopiaTheLightningSummon()
- {
- int bestBotAttack = Util.GetBestAttack(Bot);
- return Util.IsOneEnemyBetterThanValue(bestBotAttack, false);
- }
-
- ///
- /// Activate if the card is attack pos, and its attack is below 5000, when the enemy monster is attack pos or not useless faceup defense pos
- ///
- protected bool DefaultNumberS39UtopiaTheLightningEffect()
- {
- return Card.IsAttack() && Card.Attack < 5000 && (Enemy.BattlingMonster.IsAttack() || Enemy.BattlingMonster.IsFacedown() || Enemy.BattlingMonster.GetDefensePower() >= Card.Attack);
- }
-
- ///
- /// Summon when it can and should use effect.
- ///
- protected bool DefaultEvilswarmExcitonKnightSummon()
- {
- int selfCount = Bot.GetMonsterCount() + Bot.GetSpellCount() + Bot.GetHandCount();
- int oppoCount = Enemy.GetMonsterCount() + Enemy.GetSpellCount() + Enemy.GetHandCount();
- return (selfCount - 1 < oppoCount) && DefaultEvilswarmExcitonKnightEffect();
- }
-
- ///
- /// Activate when we have less cards than enemy's, or the atk sum of we is lower than enemy's.
- ///
- protected bool DefaultEvilswarmExcitonKnightEffect()
- {
- int selfCount = Bot.GetMonsterCount() + Bot.GetSpellCount();
- int oppoCount = Enemy.GetMonsterCount() + Enemy.GetSpellCount();
-
- if (selfCount < oppoCount)
- return true;
-
- int selfAttack = Bot.GetMonsters().Sum(monster => (int?)monster.GetDefensePower()) ?? 0;
- int oppoAttack = Enemy.GetMonsters().Sum(monster => (int?)monster.GetDefensePower()) ?? 0;
-
- return selfAttack < oppoAttack;
- }
-
- ///
- /// Summon in main2, or when the attack of we is lower than enemy's, but not when enemy have monster higher than 2500.
- ///
- protected bool DefaultStardustDragonSummon()
- {
- int selfBestAttack = Util.GetBestAttack(Bot);
- int oppoBestAttack = Util.GetBestPower(Enemy);
- return (selfBestAttack <= oppoBestAttack && oppoBestAttack <= 2500) || Util.IsTurn1OrMain2();
- }
-
- ///
- /// Negate enemy's destroy effect, and revive from grave.
- ///
- protected bool DefaultStardustDragonEffect()
- {
- return (Card.Location == CardLocation.Grave) || Duel.LastChainPlayer == 1;
- }
-
- ///
- /// Summon when enemy have card which we must solve.
- ///
- protected bool DefaultCastelTheSkyblasterMusketeerSummon()
- {
- return Util.GetProblematicEnemyCard() != null;
- }
-
- ///
- /// Bounce the problematic enemy card. Ignore the 1st effect.
- ///
- protected bool DefaultCastelTheSkyblasterMusketeerEffect()
- {
- if (ActivateDescription == Util.GetStringId(_CardId.CastelTheSkyblasterMusketeer, 0))
- return false;
- ClientCard target = Util.GetProblematicEnemyCard();
- if (target != null)
- {
- AI.SelectCard(0);
- AI.SelectNextCard(target);
- return true;
- }
- return false;
- }
-
- ///
- /// Summon when it should use effect, or when the attack of we is lower than enemy's, but not when enemy have monster higher than 3000.
- ///
- protected bool DefaultScarlightRedDragonArchfiendSummon()
- {
- int selfBestAttack = Util.GetBestAttack(Bot);
- int oppoBestAttack = Util.GetBestPower(Enemy);
- return (selfBestAttack <= oppoBestAttack && oppoBestAttack <= 3000) || DefaultScarlightRedDragonArchfiendEffect();
- }
-
- ///
- /// Activate when we have less monsters than enemy, or when enemy have more than 3 monsters.
- ///
- protected bool DefaultScarlightRedDragonArchfiendEffect()
- {
- int selfCount = Bot.GetMonsters().Count(monster => !monster.Equals(Card) && monster.IsSpecialSummoned && monster.HasType(CardType.Effect) && monster.Attack <= Card.Attack);
- int oppoCount = Enemy.GetMonsters().Count(monster => monster.IsSpecialSummoned && monster.HasType(CardType.Effect) && monster.Attack <= Card.Attack);
- return selfCount <= oppoCount && oppoCount > 0 || oppoCount >= 3;
- }
-
- ///
- /// Clever enough.
- ///
- protected bool DefaultHonestEffect()
- {
- if (Card.Location == CardLocation.Hand)
- {
- return Bot.BattlingMonster.IsAttack() &&
- (((Bot.BattlingMonster.Attack < Enemy.BattlingMonster.Attack) || Bot.BattlingMonster.Attack >= Enemy.LifePoints)
- || ((Bot.BattlingMonster.Attack < Enemy.BattlingMonster.Defense) && (Bot.BattlingMonster.Attack + Enemy.BattlingMonster.Attack > Enemy.BattlingMonster.Defense)));
- }
-
- if (Util.IsTurn1OrMain2() && HonestEffectCount <= 5)
- {
- HonestEffectCount++;
- return true;
- }
-
- return false;
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using YGOSharp.OCGWrapper.Enums;
+using WindBot;
+using WindBot.Game;
+using WindBot.Game.AI;
+
+namespace WindBot.Game.AI
+{
+ public abstract class DefaultExecutor : Executor
+ {
+ protected class _CardId
+ {
+ public const int JizukirutheStarDestroyingKaiju = 63941210;
+ public const int ThunderKingtheLightningstrikeKaiju = 48770333;
+ public const int DogorantheMadFlameKaiju = 93332803;
+ public const int RadiantheMultidimensionalKaiju = 28674152;
+ public const int GadarlatheMysteryDustKaiju = 36956512;
+ public const int KumongoustheStickyStringKaiju = 29726552;
+ public const int GamecieltheSeaTurtleKaiju = 55063751;
+ public const int SuperAntiKaijuWarMachineMechaDogoran = 84769941;
+
+ public const int UltimateConductorTytanno = 18940556;
+ public const int ElShaddollConstruct = 20366274;
+ public const int AllyOfJusticeCatastor = 26593852;
+
+ public const int DupeFrog = 46239604;
+ public const int MaraudingCaptain = 2460565;
+
+ public const int BlackRoseDragon = 73580471;
+ public const int JudgmentDragon = 57774843;
+ public const int TopologicTrisbaena = 72529749;
+ public const int EvilswarmExcitonKnight = 46772449;
+ public const int HarpiesFeatherDuster = 18144506;
+ public const int DarkMagicAttack = 2314238;
+ public const int MysticalSpaceTyphoon = 5318639;
+ public const int CosmicCyclone = 8267140;
+ public const int ChickenGame = 67616300;
+
+ public const int SantaClaws = 46565218;
+
+ public const int CastelTheSkyblasterMusketeer = 82633039;
+ public const int CrystalWingSynchroDragon = 50954680;
+ public const int NumberS39UtopiaTheLightning = 56832966;
+ public const int Number39Utopia = 84013237;
+ public const int UltimayaTzolkin = 1686814;
+ public const int MekkKnightCrusadiaAstram = 21887175;
+ public const int HamonLordofStrikingThunder = 32491822;
+
+ public const int MoonMirrorShield = 19508728;
+ public const int PhantomKnightsFogBlade = 25542642;
+
+ public const int VampireFraeulein = 6039967;
+ public const int InjectionFairyLily = 79575620;
+
+ public const int BlueEyesChaosMAXDragon = 55410871;
+
+ public const int AshBlossom = 14558127;
+ public const int MaxxC = 23434538;
+ public const int LockBird = 94145021;
+ public const int GhostOgreAndSnowRabbit = 59438930;
+ public const int GhostBelle = 73642296;
+ public const int EffectVeiler = 63845230;
+ public const int ArtifactLancea = 34267821;
+
+ public const int CalledByTheGrave = 24224830;
+ public const int InfiniteImpermanence = 10045474;
+ public const int GalaxySoldier = 46659709;
+ public const int MacroCosmos = 30241314;
+ public const int UpstartGoblin = 70368879;
+ public const int CyberEmergency = 60600126;
+
+ public const int EaterOfMillions = 63845230;
+
+ public const int InvokedPurgatrio = 12307878;
+ public const int ChaosAncientGearGiant = 51788412;
+ public const int UltimateAncientGearGolem = 12652643;
+
+ public const int RedDragonArchfiend = 70902743;
+
+ public const int ImperialOrder = 61740673;
+ public const int NaturiaBeast = 33198837;
+ public const int AntiSpellFragrance = 58921041;
+ }
+
+ int HonestEffectCount = 0;
+
+ protected DefaultExecutor(GameAI ai, Duel duel)
+ : base(ai, duel)
+ {
+ AddExecutor(ExecutorType.Activate, _CardId.ChickenGame, DefaultChickenGame);
+ AddExecutor(ExecutorType.Activate, _CardId.SantaClaws);
+ }
+
+ ///
+ /// Decide which card should the attacker attack.
+ ///
+ /// Card that attack.
+ /// Cards that defend.
+ /// BattlePhaseAction including the target, or null (in this situation, GameAI will check the next attacker)
+ public override BattlePhaseAction OnSelectAttackTarget(ClientCard attacker, IList defenders)
+ {
+ foreach (ClientCard defender in defenders)
+ {
+ attacker.RealPower = attacker.Attack;
+ defender.RealPower = defender.GetDefensePower();
+ if (!OnPreBattleBetween(attacker, defender))
+ continue;
+
+ if (attacker.RealPower > defender.RealPower || (attacker.RealPower >= defender.RealPower && attacker.IsLastAttacker && defender.IsAttack()))
+ return AI.Attack(attacker, defender);
+ }
+
+ if (attacker.CanDirectAttack)
+ return AI.Attack(attacker, null);
+
+ return null;
+ }
+
+ ///
+ /// Decide whether to declare attack between attacker and defender.
+ /// Can be overrided to update the RealPower of attacker for cards like Honest.
+ ///
+ /// Card that attack.
+ /// Card that defend.
+ /// false if the attack shouldn't be done.
+ public override bool OnPreBattleBetween(ClientCard attacker, ClientCard defender)
+ {
+ if (attacker.RealPower <= 0)
+ return false;
+
+ if (!attacker.IsMonsterHasPreventActivationEffectInBattle())
+ {
+ if (defender.IsMonsterInvincible() && defender.IsDefense())
+ return false;
+
+ if (defender.IsMonsterDangerous())
+ {
+ bool canIgnoreIt = !attacker.IsDisabled() && (
+ attacker.IsCode(_CardId.UltimateConductorTytanno) && defender.IsDefense() ||
+ attacker.IsCode(_CardId.ElShaddollConstruct) && defender.IsSpecialSummoned ||
+ attacker.IsCode(_CardId.AllyOfJusticeCatastor) && !defender.HasAttribute(CardAttribute.Dark));
+ if (!canIgnoreIt)
+ return false;
+ }
+
+ foreach (ClientCard equip in defender.EquipCards)
+ {
+ if (equip.IsCode(_CardId.MoonMirrorShield) && !equip.IsDisabled())
+ {
+ return false;
+ }
+ }
+
+ if (!defender.IsDisabled())
+ {
+ if (defender.IsCode(_CardId.MekkKnightCrusadiaAstram) && defender.IsAttack() && attacker.IsSpecialSummoned)
+ return false;
+
+ if (defender.IsCode(_CardId.CrystalWingSynchroDragon) && defender.IsAttack() && attacker.Level >= 5)
+ return false;
+
+ if (defender.IsCode(_CardId.AllyOfJusticeCatastor) && !attacker.HasAttribute(CardAttribute.Dark))
+ return false;
+
+ if (defender.IsCode(_CardId.NumberS39UtopiaTheLightning) && defender.IsAttack() && defender.HasXyzMaterial(2, _CardId.Number39Utopia))
+ defender.RealPower = 5000;
+
+ if (defender.IsCode(_CardId.VampireFraeulein))
+ defender.RealPower += (Enemy.LifePoints > 3000) ? 3000 : (Enemy.LifePoints - 100);
+
+ if (defender.IsCode(_CardId.InjectionFairyLily) && Enemy.LifePoints > 2000)
+ defender.RealPower += 3000;
+ }
+ }
+
+ if (!defender.IsMonsterHasPreventActivationEffectInBattle())
+ {
+ if (attacker.IsCode(_CardId.NumberS39UtopiaTheLightning) && !attacker.IsDisabled() && attacker.HasXyzMaterial(2, _CardId.Number39Utopia))
+ attacker.RealPower = 5000;
+
+ foreach (ClientCard equip in attacker.EquipCards)
+ {
+ if (equip.IsCode(_CardId.MoonMirrorShield) && !equip.IsDisabled())
+ {
+ attacker.RealPower = defender.RealPower + 100;
+ }
+ }
+ }
+
+ if (Enemy.HasInMonstersZone(_CardId.MekkKnightCrusadiaAstram, true) && !(defender).IsCode(_CardId.MekkKnightCrusadiaAstram))
+ return false;
+
+ if (Enemy.HasInMonstersZone(_CardId.DupeFrog, true) && !(defender).IsCode(_CardId.DupeFrog))
+ return false;
+
+ if (Enemy.HasInMonstersZone(_CardId.MaraudingCaptain, true) && !defender.IsCode(_CardId.MaraudingCaptain) && defender.Race == (int)CardRace.Warrior)
+ return false;
+
+ if (defender.IsCode(_CardId.UltimayaTzolkin) && !defender.IsDisabled() && Enemy.GetMonsters().Any(monster => !monster.Equals(defender) && monster.HasType(CardType.Synchro)))
+ 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;
+
+ return true;
+ }
+
+ ///
+ /// Called when the AI has to select a card position.
+ ///
+ /// Id of the card to position on the field.
+ /// List of available positions.
+ /// Selected position, or 0 if no position is set for this card.
+ public override CardPosition OnSelectPosition(int cardId, IList positions)
+ {
+ YGOSharp.OCGWrapper.NamedCard cardData = YGOSharp.OCGWrapper.NamedCard.Get(cardId);
+ if (cardData != null)
+ {
+ if (cardData.Attack == 0)
+ return CardPosition.FaceUpDefence;
+ }
+ return 0;
+ }
+
+ public override bool OnSelectBattleReplay()
+ {
+ if (Bot.BattlingMonster == null)
+ return false;
+ List defenders = new List(Duel.Fields[1].GetMonsters());
+ defenders.Sort(CardContainer.CompareDefensePower);
+ defenders.Reverse();
+ BattlePhaseAction result = OnSelectAttackTarget(Bot.BattlingMonster, defenders);
+ if (result != null && result.Action == BattlePhaseAction.BattleAction.Attack)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ public override void OnNewTurn()
+ {
+ HonestEffectCount = 0;
+ }
+
+ ///
+ /// Destroy face-down cards first, in our turn.
+ ///
+ protected bool DefaultMysticalSpaceTyphoon()
+ {
+ if (Duel.CurrentChain.Any(card => card.IsCode(_CardId.MysticalSpaceTyphoon)))
+ {
+ return false;
+ }
+
+ List spells = Enemy.GetSpells();
+ if (spells.Count == 0)
+ return false;
+
+ ClientCard selected = Enemy.SpellZone.GetFloodgate();
+
+ if (selected == null)
+ {
+ if (Duel.Player == 0)
+ selected = spells.FirstOrDefault(card => card.IsFacedown());
+ if (Duel.Player == 1)
+ selected = spells.FirstOrDefault(card => card.HasType(CardType.Continuous) || card.HasType(CardType.Equip) || card.HasType(CardType.Field));
+ }
+
+ if (selected == null)
+ return false;
+ AI.SelectCard(selected);
+ return true;
+ }
+
+ ///
+ /// Destroy face-down cards first, in our turn.
+ ///
+ protected bool DefaultCosmicCyclone()
+ {
+ foreach (ClientCard card in Duel.CurrentChain)
+ if (card.IsCode(_CardId.CosmicCyclone))
+ return false;
+ return (Bot.LifePoints > 1000) && DefaultMysticalSpaceTyphoon();
+ }
+
+ ///
+ /// Activate if avail.
+ ///
+ protected bool DefaultGalaxyCyclone()
+ {
+ List spells = Enemy.GetSpells();
+ if (spells.Count == 0)
+ return false;
+
+ ClientCard selected = null;
+
+ if (Card.Location == CardLocation.Grave)
+ {
+ selected = Util.GetBestEnemySpell(true);
+ }
+ else
+ {
+ selected = spells.FirstOrDefault(card => card.IsFacedown());
+ }
+
+ if (selected == null)
+ return false;
+
+ AI.SelectCard(selected);
+ return true;
+ }
+
+ ///
+ /// Set the highest ATK level 4+ effect enemy monster.
+ ///
+ protected bool DefaultBookOfMoon()
+ {
+ if (Util.IsAllEnemyBetter(true))
+ {
+ ClientCard monster = Enemy.GetMonsters().GetHighestAttackMonster(true);
+ if (monster != null && monster.HasType(CardType.Effect) && !monster.HasType(CardType.Link) && (monster.HasType(CardType.Xyz) || monster.Level > 4))
+ {
+ AI.SelectCard(monster);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Return problematic monster, and if this card become target, return any enemy monster.
+ ///
+ protected bool DefaultCompulsoryEvacuationDevice()
+ {
+ ClientCard target = Util.GetProblematicEnemyMonster(0, true);
+ if (target != null)
+ {
+ AI.SelectCard(target);
+ return true;
+ }
+ if (Util.IsChainTarget(Card))
+ {
+ ClientCard monster = Util.GetBestEnemyMonster(false, true);
+ if (monster != null)
+ {
+ AI.SelectCard(monster);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Revive the best monster when we don't have better one in field.
+ ///
+ protected bool DefaultCallOfTheHaunted()
+ {
+ if (!Util.IsAllEnemyBetter(true))
+ return false;
+ ClientCard selected = Bot.Graveyard.GetMatchingCards(card => card.IsCanRevive()).OrderByDescending(card => card.Attack).FirstOrDefault();
+ AI.SelectCard(selected);
+ return true;
+ }
+
+ ///
+ /// Default Scapegoat effect
+ ///
+ protected bool DefaultScapegoat()
+ {
+ if (DefaultSpellWillBeNegated()) return false;
+ if (Duel.Player == 0) return false;
+ if (Duel.Phase == DuelPhase.End) return true;
+ if (DefaultOnBecomeTarget()) return true;
+ if (Duel.Phase > DuelPhase.Main1 && Duel.Phase < DuelPhase.Main2)
+ {
+ if (Enemy.HasInMonstersZone(new[]
+ {
+ _CardId.UltimateConductorTytanno,
+ _CardId.InvokedPurgatrio,
+ _CardId.ChaosAncientGearGiant,
+ _CardId.UltimateAncientGearGolem,
+ _CardId.RedDragonArchfiend
+ }, true)) return false;
+ if (Util.GetTotalAttackingMonsterAttack(1) >= Bot.LifePoints) return true;
+ }
+ return false;
+ }
+ ///
+ /// Always active in opponent's turn.
+ ///
+ protected bool DefaultMaxxC()
+ {
+ return Duel.Player == 1;
+ }
+ ///
+ /// Always disable opponent's effect except some cards like UpstartGoblin
+ ///
+ protected bool DefaultAshBlossomAndJoyousSpring()
+ {
+ int[] ignoreList = {
+ _CardId.MacroCosmos,
+ _CardId.UpstartGoblin,
+ _CardId.CyberEmergency
+ };
+ if (Util.GetLastChainCard().IsCode(ignoreList))
+ return false;
+ if (Util.GetLastChainCard().HasSetcode(0x11e) && Util.GetLastChainCard().Location == CardLocation.Hand) // Danger! archtype hand effect
+ return false;
+ return Duel.LastChainPlayer == 1;
+ }
+ ///
+ /// Always activate unless the activating card is disabled
+ ///
+ protected bool DefaultGhostOgreAndSnowRabbit()
+ {
+ if (Util.GetLastChainCard() != null && Util.GetLastChainCard().IsDisabled())
+ return false;
+ return DefaultTrap();
+ }
+ ///
+ /// Always disable opponent's effect
+ ///
+ protected bool DefaultGhostBelleAndHauntedMansion()
+ {
+ return DefaultTrap();
+ }
+ ///
+ /// Same as DefaultBreakthroughSkill
+ ///
+ protected bool DefaultEffectVeiler()
+ {
+ if (Util.GetLastChainCard() != null && Util.GetLastChainCard().IsCode(_CardId.GalaxySoldier) && Enemy.Hand.Count >= 3) return false;
+ if (Util.ChainContainsCard(_CardId.EffectVeiler))
+ return false;
+ return DefaultBreakthroughSkill();
+ }
+ ///
+ /// Chain common hand traps
+ ///
+ protected bool DefaultCalledByTheGrave()
+ {
+ int[] targetList =
+ {
+ _CardId.MaxxC,
+ _CardId.LockBird,
+ _CardId.GhostOgreAndSnowRabbit,
+ _CardId.AshBlossom,
+ _CardId.GhostBelle,
+ _CardId.EffectVeiler,
+ _CardId.ArtifactLancea
+ };
+ if (Duel.LastChainPlayer == 1)
+ {
+ foreach (int id in targetList)
+ {
+ if (Util.GetLastChainCard().IsCode(id))
+ {
+ AI.SelectCard(id);
+ return UniqueFaceupSpell();
+ }
+ }
+ }
+ return false;
+ }
+ ///
+ /// Default InfiniteImpermanence effect
+ ///
+ protected bool DefaultInfiniteImpermanence()
+ {
+ // TODO: disable s & t
+ if (!DefaultUniqueTrap())
+ return false;
+ return DefaultDisableMonster();
+ }
+ ///
+ /// Chain the enemy monster, or disable monster like Rescue Rabbit.
+ ///
+ protected bool DefaultBreakthroughSkill()
+ {
+ if (!DefaultUniqueTrap())
+ return false;
+ return DefaultDisableMonster();
+ }
+ ///
+ /// Chain the enemy monster, or disable monster like Rescue Rabbit.
+ ///
+ protected bool DefaultDisableMonster()
+ {
+ if (Duel.Player == 1)
+ {
+ ClientCard target = Enemy.MonsterZone.GetShouldBeDisabledBeforeItUseEffectMonster();
+ if (target != null)
+ {
+ AI.SelectCard(target);
+ return true;
+ }
+ }
+
+ ClientCard LastChainCard = Util.GetLastChainCard();
+
+ if (LastChainCard != null && LastChainCard.Controller == 1 && LastChainCard.Location == CardLocation.MonsterZone &&
+ !LastChainCard.IsDisabled() && !LastChainCard.IsShouldNotBeTarget() && !LastChainCard.IsShouldNotBeSpellTrapTarget())
+ {
+ AI.SelectCard(LastChainCard);
+ return true;
+ }
+
+ if (Bot.BattlingMonster != null && Enemy.BattlingMonster != null)
+ {
+ if (!Enemy.BattlingMonster.IsDisabled() && Enemy.BattlingMonster.IsCode(_CardId.EaterOfMillions))
+ {
+ AI.SelectCard(Enemy.BattlingMonster);
+ return true;
+ }
+ }
+
+ if (Duel.Phase == DuelPhase.BattleStart && Duel.Player == 1 &&
+ Enemy.HasInMonstersZone(_CardId.NumberS39UtopiaTheLightning, true))
+ {
+ AI.SelectCard(_CardId.NumberS39UtopiaTheLightning);
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Activate only except this card is the target or we summon monsters.
+ ///
+ protected bool DefaultSolemnJudgment()
+ {
+ return !Util.IsChainTargetOnly(Card) && !(Duel.Player == 0 && Duel.LastChainPlayer == -1) && DefaultTrap();
+ }
+
+ ///
+ /// Activate only except we summon monsters.
+ ///
+ protected bool DefaultSolemnWarning()
+ {
+ return (Bot.LifePoints > 2000) && !(Duel.Player == 0 && Duel.LastChainPlayer == -1) && DefaultTrap();
+ }
+
+ ///
+ /// Activate only except we summon monsters.
+ ///
+ protected bool DefaultSolemnStrike()
+ {
+ return (Bot.LifePoints > 1500) && !(Duel.Player == 0 && Duel.LastChainPlayer == -1) && DefaultTrap();
+ }
+
+ ///
+ /// Activate when all enemy monsters have better ATK.
+ ///
+ protected bool DefaultTorrentialTribute()
+ {
+ return !Util.HasChainedTrap(0) && Util.IsAllEnemyBetter(true);
+ }
+
+ ///
+ /// Activate enemy have more S&T.
+ ///
+ protected bool DefaultHeavyStorm()
+ {
+ return Bot.GetSpellCount() < Enemy.GetSpellCount();
+ }
+
+ ///
+ /// Activate before other winds, if enemy have more than 2 S&T.
+ ///
+ protected bool DefaultHarpiesFeatherDusterFirst()
+ {
+ return Enemy.GetSpellCount() >= 2;
+ }
+
+ ///
+ /// Activate when one enemy monsters have better ATK.
+ ///
+ protected bool DefaultHammerShot()
+ {
+ return Util.IsOneEnemyBetter(true);
+ }
+
+ ///
+ /// Activate when one enemy monsters have better ATK or DEF.
+ ///
+ protected bool DefaultDarkHole()
+ {
+ return Util.IsOneEnemyBetter();
+ }
+
+ ///
+ /// Activate when one enemy monsters have better ATK or DEF.
+ ///
+ protected bool DefaultRaigeki()
+ {
+ return Util.IsOneEnemyBetter();
+ }
+
+ ///
+ /// Activate when one enemy monsters have better ATK or DEF.
+ ///
+ protected bool DefaultSmashingGround()
+ {
+ return Util.IsOneEnemyBetter();
+ }
+
+ ///
+ /// Activate when we have more than 15 cards in deck.
+ ///
+ protected bool DefaultPotOfDesires()
+ {
+ return Bot.Deck.Count > 15;
+ }
+
+ ///
+ /// Set traps only and avoid block the activation of other cards.
+ ///
+ protected bool DefaultSpellSet()
+ {
+ return (Card.IsTrap() || Card.HasType(CardType.QuickPlay)) && Bot.GetSpellCountWithoutField() < 4;
+ }
+
+ ///
+ /// Summon with tributes ATK lower.
+ ///
+ protected bool DefaultTributeSummon()
+ {
+ if (!UniqueFaceupMonster())
+ return false;
+ int tributecount = (int)Math.Ceiling((Card.Level - 4.0d) / 2.0d);
+ for (int j = 0; j < 7; ++j)
+ {
+ ClientCard tributeCard = Bot.MonsterZone[j];
+ if (tributeCard == null) continue;
+ if (tributeCard.GetDefensePower() < Card.Attack)
+ tributecount--;
+ }
+ return tributecount <= 0;
+ }
+
+ ///
+ /// Activate when we have no field.
+ ///
+ protected bool DefaultField()
+ {
+ return Bot.SpellZone[5] == null;
+ }
+
+ ///
+ /// Turn if all enemy is better.
+ ///
+ protected bool DefaultMonsterRepos()
+ {
+ if (Card.IsFaceup() && Card.IsDefense() && Card.Attack == 0)
+ return false;
+
+ if (Enemy.HasInMonstersZone(_CardId.BlueEyesChaosMAXDragon, true) &&
+ Card.IsAttack() && (4000 - Card.Defense) * 2 > (4000 - Card.Attack))
+ return false;
+ if (Enemy.HasInMonstersZone(_CardId.BlueEyesChaosMAXDragon, true) &&
+ Card.IsDefense() && Card.IsFaceup() &&
+ (4000 - Card.Defense) * 2 > (4000 - Card.Attack))
+ return true;
+
+ bool enemyBetter = Util.IsAllEnemyBetter(true);
+ if (Card.IsAttack() && enemyBetter)
+ return true;
+ if (Card.IsDefense() && !enemyBetter && Card.Attack >= Card.Defense)
+ return true;
+
+ return false;
+ }
+
+ ///
+ /// If spell will be negated
+ ///
+ protected bool DefaultSpellWillBeNegated()
+ {
+ return Bot.HasInSpellZone(_CardId.ImperialOrder, true, true) || Enemy.HasInSpellZone(_CardId.ImperialOrder, true) || Enemy.HasInMonstersZone(_CardId.NaturiaBeast, true);
+ }
+
+ ///
+ /// If spell must set first to activate
+ ///
+ protected bool DefaultSpellMustSetFirst()
+ {
+ ClientCard card = null;
+ foreach (ClientCard check in Bot.GetSpells())
+ {
+ if (check.IsCode(_CardId.AntiSpellFragrance) && !check.IsDisabled())
+ card = check;
+ }
+ if (card != null && card.IsFaceup())
+ return true;
+ return Bot.HasInSpellZone(_CardId.AntiSpellFragrance, true, true) || Enemy.HasInSpellZone(_CardId.AntiSpellFragrance, true);
+ }
+
+ ///
+ /// if spell/trap is the target or enermy activate HarpiesFeatherDuster
+ ///
+ protected bool DefaultOnBecomeTarget()
+ {
+ if (Util.IsChainTarget(Card)) return true;
+ int[] destroyAllList =
+ {
+ _CardId.EvilswarmExcitonKnight,
+ _CardId.BlackRoseDragon,
+ _CardId.JudgmentDragon,
+ _CardId.TopologicTrisbaena
+ };
+ int[] destroyAllOpponentList =
+ {
+ _CardId.HarpiesFeatherDuster,
+ _CardId.DarkMagicAttack
+ };
+
+ if (Util.ChainContainsCard(destroyAllList)) return true;
+ if (Enemy.HasInSpellZone(destroyAllOpponentList, true)) return true;
+ // TODO: ChainContainsCard(id, player)
+ return false;
+ }
+ ///
+ /// Chain enemy activation or summon.
+ ///
+ protected bool DefaultTrap()
+ {
+ return (Duel.LastChainPlayer == -1 && Duel.LastSummonPlayer != 0) || Duel.LastChainPlayer == 1;
+ }
+
+ ///
+ /// Activate when avail and no other our trap card in this chain or face-up.
+ ///
+ protected bool DefaultUniqueTrap()
+ {
+ if (Util.HasChainedTrap(0))
+ return false;
+
+ return UniqueFaceupSpell();
+ }
+
+ ///
+ /// Check no other our spell or trap card with same name face-up.
+ ///
+ protected bool UniqueFaceupSpell()
+ {
+ return !Bot.GetSpells().Any(card => card.IsCode(Card.Id) && card.IsFaceup());
+ }
+
+ ///
+ /// Check no other our monster card with same name face-up.
+ ///
+ protected bool UniqueFaceupMonster()
+ {
+ return !Bot.GetMonsters().Any(card => card.IsCode(Card.Id) && card.IsFaceup());
+ }
+
+ ///
+ /// Dumb way to avoid the bot chain in mess.
+ ///
+ protected bool DefaultDontChainMyself()
+ {
+ if (Executors.Any(exec => exec.Type == Type && exec.CardId == Card.Id))
+ return false;
+ return Duel.LastChainPlayer != 0;
+ }
+
+ ///
+ /// Draw when we have lower LP, or destroy it. Can be overrided.
+ ///
+ protected bool DefaultChickenGame()
+ {
+ if (Executors.Count(exec => exec.Type == Type && exec.CardId == Card.Id) > 1)
+ return false;
+ if (Bot.LifePoints <= 1000)
+ return false;
+ if (Bot.LifePoints <= Enemy.LifePoints && ActivateDescription == Util.GetStringId(_CardId.ChickenGame, 0))
+ return true;
+ if (Bot.LifePoints > Enemy.LifePoints && ActivateDescription == Util.GetStringId(_CardId.ChickenGame, 1))
+ return true;
+ return false;
+ }
+
+ ///
+ /// Draw when we have Dark monster in hand,and banish random one. Can be overrided.
+ ///
+ protected bool DefaultAllureofDarkness()
+ {
+ ClientCard target = Bot.Hand.FirstOrDefault(card => card.HasAttribute(CardAttribute.Dark));
+ return target != null;
+ }
+
+ ///
+ /// Clever enough.
+ ///
+ protected bool DefaultDimensionalBarrier()
+ {
+ const int RITUAL = 0;
+ const int FUSION = 1;
+ const int SYNCHRO = 2;
+ const int XYZ = 3;
+ const int PENDULUM = 4;
+ if (Duel.Player != 0)
+ {
+ List monsters = Enemy.GetMonsters();
+ int[] levels = new int[13];
+ bool tuner = false;
+ 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))
+ {
+ nontuner = true;
+ levels[monster.Level] = levels[monster.Level] + 1;
+ }
+
+ if (monster.IsOneForXyz())
+ {
+ AI.SelectOption(XYZ);
+ return true;
+ }
+ }
+ if (tuner && nontuner)
+ {
+ AI.SelectOption(SYNCHRO);
+ return true;
+ }
+ for (int i=1; i<=12; i++)
+ {
+ if (levels[i]>1)
+ {
+ AI.SelectOption(XYZ);
+ return true;
+ }
+ }
+ ClientCard l = Enemy.SpellZone[6];
+ ClientCard r = Enemy.SpellZone[7];
+ if (l != null && r != null && l.LScale != r.RScale)
+ {
+ AI.SelectOption(PENDULUM);
+ return true;
+ }
+ }
+ ClientCard lastchaincard = Util.GetLastChainCard();
+ if (Duel.LastChainPlayer == 1 && lastchaincard != null && !lastchaincard.IsDisabled())
+ {
+ if (lastchaincard.HasType(CardType.Ritual))
+ {
+ AI.SelectOption(RITUAL);
+ return true;
+ }
+ if (lastchaincard.HasType(CardType.Fusion))
+ {
+ AI.SelectOption(FUSION);
+ return true;
+ }
+ if (lastchaincard.HasType(CardType.Synchro))
+ {
+ AI.SelectOption(SYNCHRO);
+ return true;
+ }
+ if (lastchaincard.HasType(CardType.Xyz))
+ {
+ AI.SelectOption(XYZ);
+ return true;
+ }
+ if (lastchaincard.IsFusionSpell())
+ {
+ AI.SelectOption(FUSION);
+ return true;
+ }
+ }
+ if (Util.IsChainTarget(Card))
+ {
+ AI.SelectOption(XYZ);
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Clever enough
+ ///
+ protected bool DefaultInterruptedKaijuSlumber()
+ {
+ if (Card.Location == CardLocation.Grave)
+ {
+ AI.SelectCard(
+ _CardId.GamecieltheSeaTurtleKaiju,
+ _CardId.KumongoustheStickyStringKaiju,
+ _CardId.GadarlatheMysteryDustKaiju,
+ _CardId.RadiantheMultidimensionalKaiju,
+ _CardId.DogorantheMadFlameKaiju,
+ _CardId.ThunderKingtheLightningstrikeKaiju,
+ _CardId.JizukirutheStarDestroyingKaiju
+ );
+ return true;
+ }
+
+ if (DefaultDarkHole())
+ {
+ AI.SelectCard(
+ _CardId.JizukirutheStarDestroyingKaiju,
+ _CardId.ThunderKingtheLightningstrikeKaiju,
+ _CardId.DogorantheMadFlameKaiju,
+ _CardId.RadiantheMultidimensionalKaiju,
+ _CardId.GadarlatheMysteryDustKaiju,
+ _CardId.KumongoustheStickyStringKaiju,
+ _CardId.GamecieltheSeaTurtleKaiju
+ );
+ AI.SelectNextCard(
+ _CardId.SuperAntiKaijuWarMachineMechaDogoran,
+ _CardId.GamecieltheSeaTurtleKaiju,
+ _CardId.KumongoustheStickyStringKaiju,
+ _CardId.GadarlatheMysteryDustKaiju,
+ _CardId.RadiantheMultidimensionalKaiju,
+ _CardId.DogorantheMadFlameKaiju,
+ _CardId.ThunderKingtheLightningstrikeKaiju
+ );
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Clever enough.
+ ///
+ protected bool DefaultKaijuSpsummon()
+ {
+ IList kaijus = new[] {
+ _CardId.JizukirutheStarDestroyingKaiju,
+ _CardId.GadarlatheMysteryDustKaiju,
+ _CardId.GamecieltheSeaTurtleKaiju,
+ _CardId.RadiantheMultidimensionalKaiju,
+ _CardId.KumongoustheStickyStringKaiju,
+ _CardId.ThunderKingtheLightningstrikeKaiju,
+ _CardId.DogorantheMadFlameKaiju,
+ _CardId.SuperAntiKaijuWarMachineMechaDogoran
+ };
+ foreach (ClientCard monster in Enemy.GetMonsters())
+ {
+ if (monster.IsCode(kaijus))
+ return Card.GetDefensePower() > monster.GetDefensePower();
+ }
+ ClientCard card = Enemy.MonsterZone.GetFloodgate();
+ if (card != null)
+ {
+ AI.SelectCard(card);
+ return true;
+ }
+ card = Enemy.MonsterZone.GetDangerousMonster();
+ if (card != null)
+ {
+ AI.SelectCard(card);
+ return true;
+ }
+ card = Util.GetOneEnemyBetterThanValue(Card.GetDefensePower());
+ if (card != null)
+ {
+ AI.SelectCard(card);
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Summon when we don't have monster attack higher than enemy's.
+ ///
+ protected bool DefaultNumberS39UtopiaTheLightningSummon()
+ {
+ int bestBotAttack = Util.GetBestAttack(Bot);
+ return Util.IsOneEnemyBetterThanValue(bestBotAttack, false);
+ }
+
+ ///
+ /// Activate if the card is attack pos, and its attack is below 5000, when the enemy monster is attack pos or not useless faceup defense pos
+ ///
+ protected bool DefaultNumberS39UtopiaTheLightningEffect()
+ {
+ return Card.IsAttack() && Card.Attack < 5000 && (Enemy.BattlingMonster.IsAttack() || Enemy.BattlingMonster.IsFacedown() || Enemy.BattlingMonster.GetDefensePower() >= Card.Attack);
+ }
+
+ ///
+ /// Summon when it can and should use effect.
+ ///
+ protected bool DefaultEvilswarmExcitonKnightSummon()
+ {
+ int selfCount = Bot.GetMonsterCount() + Bot.GetSpellCount() + Bot.GetHandCount();
+ int oppoCount = Enemy.GetMonsterCount() + Enemy.GetSpellCount() + Enemy.GetHandCount();
+ return (selfCount - 1 < oppoCount) && DefaultEvilswarmExcitonKnightEffect();
+ }
+
+ ///
+ /// Activate when we have less cards than enemy's, or the atk sum of we is lower than enemy's.
+ ///
+ protected bool DefaultEvilswarmExcitonKnightEffect()
+ {
+ int selfCount = Bot.GetMonsterCount() + Bot.GetSpellCount();
+ int oppoCount = Enemy.GetMonsterCount() + Enemy.GetSpellCount();
+
+ if (selfCount < oppoCount)
+ return true;
+
+ int selfAttack = Bot.GetMonsters().Sum(monster => (int?)monster.GetDefensePower()) ?? 0;
+ int oppoAttack = Enemy.GetMonsters().Sum(monster => (int?)monster.GetDefensePower()) ?? 0;
+
+ return selfAttack < oppoAttack;
+ }
+
+ ///
+ /// Summon in main2, or when the attack of we is lower than enemy's, but not when enemy have monster higher than 2500.
+ ///
+ protected bool DefaultStardustDragonSummon()
+ {
+ int selfBestAttack = Util.GetBestAttack(Bot);
+ int oppoBestAttack = Util.GetBestPower(Enemy);
+ return (selfBestAttack <= oppoBestAttack && oppoBestAttack <= 2500) || Util.IsTurn1OrMain2();
+ }
+
+ ///
+ /// Negate enemy's destroy effect, and revive from grave.
+ ///
+ protected bool DefaultStardustDragonEffect()
+ {
+ return (Card.Location == CardLocation.Grave) || Duel.LastChainPlayer == 1;
+ }
+
+ ///
+ /// Summon when enemy have card which we must solve.
+ ///
+ protected bool DefaultCastelTheSkyblasterMusketeerSummon()
+ {
+ return Util.GetProblematicEnemyCard() != null;
+ }
+
+ ///
+ /// Bounce the problematic enemy card. Ignore the 1st effect.
+ ///
+ protected bool DefaultCastelTheSkyblasterMusketeerEffect()
+ {
+ if (ActivateDescription == Util.GetStringId(_CardId.CastelTheSkyblasterMusketeer, 0))
+ return false;
+ ClientCard target = Util.GetProblematicEnemyCard();
+ if (target != null)
+ {
+ AI.SelectCard(0);
+ AI.SelectNextCard(target);
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Summon when it should use effect, or when the attack of we is lower than enemy's, but not when enemy have monster higher than 3000.
+ ///
+ protected bool DefaultScarlightRedDragonArchfiendSummon()
+ {
+ int selfBestAttack = Util.GetBestAttack(Bot);
+ int oppoBestAttack = Util.GetBestPower(Enemy);
+ return (selfBestAttack <= oppoBestAttack && oppoBestAttack <= 3000) || DefaultScarlightRedDragonArchfiendEffect();
+ }
+
+ ///
+ /// Activate when we have less monsters than enemy, or when enemy have more than 3 monsters.
+ ///
+ protected bool DefaultScarlightRedDragonArchfiendEffect()
+ {
+ int selfCount = Bot.GetMonsters().Count(monster => !monster.Equals(Card) && monster.IsSpecialSummoned && monster.HasType(CardType.Effect) && monster.Attack <= Card.Attack);
+ int oppoCount = Enemy.GetMonsters().Count(monster => monster.IsSpecialSummoned && monster.HasType(CardType.Effect) && monster.Attack <= Card.Attack);
+ return selfCount <= oppoCount && oppoCount > 0 || oppoCount >= 3;
+ }
+
+ ///
+ /// Clever enough.
+ ///
+ protected bool DefaultHonestEffect()
+ {
+ if (Card.Location == CardLocation.Hand)
+ {
+ return Bot.BattlingMonster.IsAttack() &&
+ (((Bot.BattlingMonster.Attack < Enemy.BattlingMonster.Attack) || Bot.BattlingMonster.Attack >= Enemy.LifePoints)
+ || ((Bot.BattlingMonster.Attack < Enemy.BattlingMonster.Defense) && (Bot.BattlingMonster.Attack + Enemy.BattlingMonster.Attack > Enemy.BattlingMonster.Defense)));
+ }
+
+ if (Util.IsTurn1OrMain2() && HonestEffectCount <= 5)
+ {
+ HonestEffectCount++;
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/Game/AI/Enums/DangerousMonster.cs b/ExecutorBase/Game/AI/Enums/DangerousMonster.cs
similarity index 96%
rename from Game/AI/Enums/DangerousMonster.cs
rename to ExecutorBase/Game/AI/Enums/DangerousMonster.cs
index 66276534..067d3935 100644
--- a/Game/AI/Enums/DangerousMonster.cs
+++ b/ExecutorBase/Game/AI/Enums/DangerousMonster.cs
@@ -1,28 +1,28 @@
-namespace WindBot.Game.AI.Enums
-{
- ///
- /// Cards that are dangerous to attack.
- ///
- public enum DangerousMonster
- {
- LionHeart = 54366836,
- Yubel = 78371393,
- YubelIncarnate = 4779091,
- YubelNightmare = 31764700,
- ZaphionTheTimelord = 28929131,
- SadionTheTimelord = 65314286,
- MetaionTheTimelord = 74530899,
- KamionTheTimelord = 91712985,
- LazionTheTimelord = 92435533,
- MichionTheTimelord = 7733560,
- HailonTheTimelord = 34137269,
- RaphionTheTimelord = 60222213,
- GabrionTheTimelord = 6616912,
- SandaionTheTimelord = 33015627,
- EaterOfMillions = 63845230,
- ElShaddollConstruct = 20366274,
- ZushintheSleepingGiant = 67547370,
- Heart_eartHDragon = 97403510,
- DaigustoSphreeze = 29552709,
- }
-}
+namespace WindBot.Game.AI.Enums
+{
+ ///
+ /// Cards that are dangerous to attack.
+ ///
+ public enum DangerousMonster
+ {
+ LionHeart = 54366836,
+ Yubel = 78371393,
+ YubelIncarnate = 4779091,
+ YubelNightmare = 31764700,
+ ZaphionTheTimelord = 28929131,
+ SadionTheTimelord = 65314286,
+ MetaionTheTimelord = 74530899,
+ KamionTheTimelord = 91712985,
+ LazionTheTimelord = 92435533,
+ MichionTheTimelord = 7733560,
+ HailonTheTimelord = 34137269,
+ RaphionTheTimelord = 60222213,
+ GabrionTheTimelord = 6616912,
+ SandaionTheTimelord = 33015627,
+ EaterOfMillions = 63845230,
+ ElShaddollConstruct = 20366274,
+ ZushintheSleepingGiant = 67547370,
+ Heart_eartHDragon = 97403510,
+ DaigustoSphreeze = 29552709,
+ }
+}
diff --git a/Game/AI/Enums/Floodgate.cs b/ExecutorBase/Game/AI/Enums/Floodgate.cs
similarity index 100%
rename from Game/AI/Enums/Floodgate.cs
rename to ExecutorBase/Game/AI/Enums/Floodgate.cs
diff --git a/Game/AI/Enums/FusionSpell.cs b/ExecutorBase/Game/AI/Enums/FusionSpell.cs
similarity index 100%
rename from Game/AI/Enums/FusionSpell.cs
rename to ExecutorBase/Game/AI/Enums/FusionSpell.cs
diff --git a/Game/AI/Enums/InvincibleMonster.cs b/ExecutorBase/Game/AI/Enums/InvincibleMonster.cs
similarity index 97%
rename from Game/AI/Enums/InvincibleMonster.cs
rename to ExecutorBase/Game/AI/Enums/InvincibleMonster.cs
index bd9bc680..9399125e 100644
--- a/Game/AI/Enums/InvincibleMonster.cs
+++ b/ExecutorBase/Game/AI/Enums/InvincibleMonster.cs
@@ -1,71 +1,71 @@
-namespace WindBot.Game.AI.Enums
-{
- ///
- /// Cards that are invincible to battle.
- ///
- public enum InvincibleMonster
- {
- SpiritReaper = 23205979,
- YubelTheUltimateNightmare = 31764700,
- YubelTerrorIncarnate = 4779091,
- SandaionTheTimelord = 33015627,
- DarknessNeosphere = 60417395,
- GabrionTheTimelord = 6616912,
- MichionTheTimelord = 7733560,
- ZaphionTheTimelord = 28929131,
- HailonTheTimelord = 34137269,
- RaphionTheTimelord = 60222213,
- SadionTheTimelord = 65314286,
- MetaionTheTimelord = 74530899,
- Yubel = 78371393,
- KamionTheTimelord = 91712985,
- LazionTheTimelord = 92435533,
- CloudianEyeofTheTyphoon = 57610714,
- GimmickPuppetShadowFeeler = 34620088,
- TheLegendaryFishermanIII = 44968687,
- CastleGate = 36931229,
- CloudianNimbusman = 20003527,
- ExodiaNecross = 12600382,
- Gellenduo = 11662742,
- CloudianAltus = 79703905,
- CloudianStormDragon = 13474291,
- CloudianCirrostratus = 43318266,
- CloudianTurbulence = 16197610,
- CloudianAcidCloud = 17810268,
- SuperheavySamuraiBlueBrawler = 41628550,
- DinoSewing = 27143874,
- Marshmallon = 31305911,
- ShibaWarriorTaro = 27416701,
- XSaberPashuul = 23093604,
- SuperheavySamuraiBlowtorch = 7864030,
- VijamTheCubicSeed = 15610297,
- ArcanaForce0TheFool = 62892347,
- ReptilianneNaga = 79491903,
- AbyssStungray = 97232518,
- ArmityleTheChaosPhantom = 43378048,
- BlueEyesTwinBurstDragon = 2129638,
- GladiatorBeastNerokius = 29357956,
- MaskedHERODivineWind = 22093873,
- ElementalHEROShiningPhoenixEnforcer = 88820235,
- LunalightCatDancer = 51777272,
- ElementalHEROPhoenixEnforcer = 41436536,
- BloomDivaTheMelodiousChoir = 84988419,
- ReaperonTheNightmare = 85684223,
- BeelzeusofTheDiabolicDragons = 8763963,
- DragocytosCorruptedNethersoulDragon = 21435914,
- BeelzeofTheDiabolicDragons = 34408491,
- BlackwingArmorMaster = 69031175,
- DaigustoSphreeze = 29552709,
- DarkDiviner = 31919988,
- NumberC92HearteartHChaosDragon = 47017574,
- Number92HearteartHDragon = 97403510,
- Number51FinisherTheStrongArm = 56292140,
- NumberC96DarkStorm = 77205367,
- NumberF0UtopicFutureFutureSlash = 43490025,
- NumberF0UtopicFuture = 65305468,
- GoukiTheGiantOgre = 47946130,
- BorrelswordDragon = 85289965,
- NumberF0UtopicFutureDragon = 26973555,
- BorrelendDragon = 98630720
- }
-}
+namespace WindBot.Game.AI.Enums
+{
+ ///
+ /// Cards that are invincible to battle.
+ ///
+ public enum InvincibleMonster
+ {
+ SpiritReaper = 23205979,
+ YubelTheUltimateNightmare = 31764700,
+ YubelTerrorIncarnate = 4779091,
+ SandaionTheTimelord = 33015627,
+ DarknessNeosphere = 60417395,
+ GabrionTheTimelord = 6616912,
+ MichionTheTimelord = 7733560,
+ ZaphionTheTimelord = 28929131,
+ HailonTheTimelord = 34137269,
+ RaphionTheTimelord = 60222213,
+ SadionTheTimelord = 65314286,
+ MetaionTheTimelord = 74530899,
+ Yubel = 78371393,
+ KamionTheTimelord = 91712985,
+ LazionTheTimelord = 92435533,
+ CloudianEyeofTheTyphoon = 57610714,
+ GimmickPuppetShadowFeeler = 34620088,
+ TheLegendaryFishermanIII = 44968687,
+ CastleGate = 36931229,
+ CloudianNimbusman = 20003527,
+ ExodiaNecross = 12600382,
+ Gellenduo = 11662742,
+ CloudianAltus = 79703905,
+ CloudianStormDragon = 13474291,
+ CloudianCirrostratus = 43318266,
+ CloudianTurbulence = 16197610,
+ CloudianAcidCloud = 17810268,
+ SuperheavySamuraiBlueBrawler = 41628550,
+ DinoSewing = 27143874,
+ Marshmallon = 31305911,
+ ShibaWarriorTaro = 27416701,
+ XSaberPashuul = 23093604,
+ SuperheavySamuraiBlowtorch = 7864030,
+ VijamTheCubicSeed = 15610297,
+ ArcanaForce0TheFool = 62892347,
+ ReptilianneNaga = 79491903,
+ AbyssStungray = 97232518,
+ ArmityleTheChaosPhantom = 43378048,
+ BlueEyesTwinBurstDragon = 2129638,
+ GladiatorBeastNerokius = 29357956,
+ MaskedHERODivineWind = 22093873,
+ ElementalHEROShiningPhoenixEnforcer = 88820235,
+ LunalightCatDancer = 51777272,
+ ElementalHEROPhoenixEnforcer = 41436536,
+ BloomDivaTheMelodiousChoir = 84988419,
+ ReaperonTheNightmare = 85684223,
+ BeelzeusofTheDiabolicDragons = 8763963,
+ DragocytosCorruptedNethersoulDragon = 21435914,
+ BeelzeofTheDiabolicDragons = 34408491,
+ BlackwingArmorMaster = 69031175,
+ DaigustoSphreeze = 29552709,
+ DarkDiviner = 31919988,
+ NumberC92HearteartHChaosDragon = 47017574,
+ Number92HearteartHDragon = 97403510,
+ Number51FinisherTheStrongArm = 56292140,
+ NumberC96DarkStorm = 77205367,
+ NumberF0UtopicFutureFutureSlash = 43490025,
+ NumberF0UtopicFuture = 65305468,
+ GoukiTheGiantOgre = 47946130,
+ BorrelswordDragon = 85289965,
+ NumberF0UtopicFutureDragon = 26973555,
+ BorrelendDragon = 98630720
+ }
+}
diff --git a/Game/AI/Enums/OneForXyz.cs b/ExecutorBase/Game/AI/Enums/OneForXyz.cs
similarity index 100%
rename from Game/AI/Enums/OneForXyz.cs
rename to ExecutorBase/Game/AI/Enums/OneForXyz.cs
diff --git a/Game/AI/Enums/PreventActivationEffectInBattle.cs b/ExecutorBase/Game/AI/Enums/PreventActivationEffectInBattle.cs
similarity index 100%
rename from Game/AI/Enums/PreventActivationEffectInBattle.cs
rename to ExecutorBase/Game/AI/Enums/PreventActivationEffectInBattle.cs
diff --git a/Game/AI/Enums/ShouldBeDisabledBeforeItUseEffectMonster.cs b/ExecutorBase/Game/AI/Enums/ShouldBeDisabledBeforeItUseEffectMonster.cs
similarity index 97%
rename from Game/AI/Enums/ShouldBeDisabledBeforeItUseEffectMonster.cs
rename to ExecutorBase/Game/AI/Enums/ShouldBeDisabledBeforeItUseEffectMonster.cs
index ff5df104..547e0c16 100644
--- a/Game/AI/Enums/ShouldBeDisabledBeforeItUseEffectMonster.cs
+++ b/ExecutorBase/Game/AI/Enums/ShouldBeDisabledBeforeItUseEffectMonster.cs
@@ -1,61 +1,61 @@
-namespace WindBot.Game.AI.Enums
-{
- ///
- /// Monsters that release or banish itself to use effect. So them should be disabled (with Breakthrough Skill) before it use effect.
- ///
- public enum ShouldBeDisabledBeforeItUseEffectMonster
- {
- MachinaMegaform = 51617185,
- DarkSummoningBeast = 87917187,
- GemKnightAlexandrite = 90019393,
- RedEyesRetroDragon = 53485634,
- DeepSweeper = 8649148,
- BeastWarriorPuma = 16796157,
- ZefrasaberSwordmasteroftheNekroz = 84388461,
- CipherWing = 81974607,
- MadolcheAnjelly = 34680482,
- PlanetPathfinder = 97526666,
- RescueCat = 14878871,
- RescueHamster = 50485594,
- RescueFerret = 56343672,
- RescueRabbit = 85138716,
- GalaxyWizard = 98555327,
- Backlinker = 71172240,
- Merlin = 3580032,
- CrystalVanguard = 87475570,
- TemperanceofProphecy = 87608852,
- Kuribandit = 16404809,
- PhotonLizard = 38973775,
- SuperheavySamuraiFlutist = 27978707,
- ConstellarRasalhague = 70624184,
- CardcarD = 45812361,
- UnifloraMysticalBeastoftheForest = 36318200,
- BusterWhelpoftheDestructionSwordsman = 49823708,
- GalaxyEyesCloudragon = 9260791,
- SylvanPrincessprout = 20579538,
- AltergeistPixiel = 57769391,
- AbyssActorExtras = 88412339,
- PerformapalTrumpWitch = 91584698,
- RaidraptorLastStrix = 97219708,
- MythicalBeastJackal = 91182675,
- TimeMaiden = 27107590,
- SuperQuantalFairyAlphan = 58753372,
- TheBlackStoneofLegend = 66574418,
- PaladinofDarkDragon = 71408082,
- PaladinofPhotonDragon = 85346853,
- TwinPhotonLizard = 29455728,
- TimeThiefRegulator = 19891131,
- MathmechNabla = 53577438,
- NidhoggGeneraiderBossofIce = 49275969,
- HoarrGeneraiderBossofRumbling = 68199168,
- RedFamiliar = 8372133,
- AccesscodeTalker = 86066372,
- ChaosSummoningBeast = 27439792,
-
- CosmoBrain = 85679527,
- ShiranuiSolitaire = 94801854,
- Mixeroid = 71340250,
- LonefireBlossom = 48686504,
- BrotherhoodoftheFireFist_Leopard = 39699564
- }
-}
+namespace WindBot.Game.AI.Enums
+{
+ ///
+ /// Monsters that release or banish itself to use effect. So them should be disabled (with Breakthrough Skill) before it use effect.
+ ///
+ public enum ShouldBeDisabledBeforeItUseEffectMonster
+ {
+ MachinaMegaform = 51617185,
+ DarkSummoningBeast = 87917187,
+ GemKnightAlexandrite = 90019393,
+ RedEyesRetroDragon = 53485634,
+ DeepSweeper = 8649148,
+ BeastWarriorPuma = 16796157,
+ ZefrasaberSwordmasteroftheNekroz = 84388461,
+ CipherWing = 81974607,
+ MadolcheAnjelly = 34680482,
+ PlanetPathfinder = 97526666,
+ RescueCat = 14878871,
+ RescueHamster = 50485594,
+ RescueFerret = 56343672,
+ RescueRabbit = 85138716,
+ GalaxyWizard = 98555327,
+ Backlinker = 71172240,
+ Merlin = 3580032,
+ CrystalVanguard = 87475570,
+ TemperanceofProphecy = 87608852,
+ Kuribandit = 16404809,
+ PhotonLizard = 38973775,
+ SuperheavySamuraiFlutist = 27978707,
+ ConstellarRasalhague = 70624184,
+ CardcarD = 45812361,
+ UnifloraMysticalBeastoftheForest = 36318200,
+ BusterWhelpoftheDestructionSwordsman = 49823708,
+ GalaxyEyesCloudragon = 9260791,
+ SylvanPrincessprout = 20579538,
+ AltergeistPixiel = 57769391,
+ AbyssActorExtras = 88412339,
+ PerformapalTrumpWitch = 91584698,
+ RaidraptorLastStrix = 97219708,
+ MythicalBeastJackal = 91182675,
+ TimeMaiden = 27107590,
+ SuperQuantalFairyAlphan = 58753372,
+ TheBlackStoneofLegend = 66574418,
+ PaladinofDarkDragon = 71408082,
+ PaladinofPhotonDragon = 85346853,
+ TwinPhotonLizard = 29455728,
+ TimeThiefRegulator = 19891131,
+ MathmechNabla = 53577438,
+ NidhoggGeneraiderBossofIce = 49275969,
+ HoarrGeneraiderBossofRumbling = 68199168,
+ RedFamiliar = 8372133,
+ AccesscodeTalker = 86066372,
+ ChaosSummoningBeast = 27439792,
+
+ CosmoBrain = 85679527,
+ ShiranuiSolitaire = 94801854,
+ Mixeroid = 71340250,
+ LonefireBlossom = 48686504,
+ BrotherhoodoftheFireFist_Leopard = 39699564
+ }
+}
diff --git a/Game/AI/Enums/ShouldNotBeMonsterTarget.cs b/ExecutorBase/Game/AI/Enums/ShouldNotBeMonsterTarget.cs
similarity index 97%
rename from Game/AI/Enums/ShouldNotBeMonsterTarget.cs
rename to ExecutorBase/Game/AI/Enums/ShouldNotBeMonsterTarget.cs
index b5cb0f6f..855824e2 100644
--- a/Game/AI/Enums/ShouldNotBeMonsterTarget.cs
+++ b/ExecutorBase/Game/AI/Enums/ShouldNotBeMonsterTarget.cs
@@ -1,19 +1,19 @@
-namespace WindBot.Game.AI.Enums
-{
- ///
- /// Cards that are can't be selected as target of monster's effect, or immuned to monster's effect.
- /// So them shouldn't be tried to be selected as target of monster at most times.
- ///
- public enum ShouldNotBeMonsterTarget
- {
- TheLegendaryFishermanII = 19801646,
- GaiaDraketheUniversalForce = 58601383,
- FirstoftheDragons = 10817524,
- Tatsunoko = 55863245,
- CXyzSimontheGreatMoralLeader = 41147577,
- PaleozoicAnomalocaris = 61307542,
- PaleozoicOpabinia = 37649320,
- BorreloadDragon = 31833038,
- BorrelendDragon = 98630720
- }
-}
+namespace WindBot.Game.AI.Enums
+{
+ ///
+ /// Cards that are can't be selected as target of monster's effect, or immuned to monster's effect.
+ /// So them shouldn't be tried to be selected as target of monster at most times.
+ ///
+ public enum ShouldNotBeMonsterTarget
+ {
+ TheLegendaryFishermanII = 19801646,
+ GaiaDraketheUniversalForce = 58601383,
+ FirstoftheDragons = 10817524,
+ Tatsunoko = 55863245,
+ CXyzSimontheGreatMoralLeader = 41147577,
+ PaleozoicAnomalocaris = 61307542,
+ PaleozoicOpabinia = 37649320,
+ BorreloadDragon = 31833038,
+ BorrelendDragon = 98630720
+ }
+}
diff --git a/Game/AI/Enums/ShouldNotBeSpellTarget.cs b/ExecutorBase/Game/AI/Enums/ShouldNotBeSpellTarget.cs
similarity index 97%
rename from Game/AI/Enums/ShouldNotBeSpellTarget.cs
rename to ExecutorBase/Game/AI/Enums/ShouldNotBeSpellTarget.cs
index ba8e69c6..fa78eaf9 100644
--- a/Game/AI/Enums/ShouldNotBeSpellTarget.cs
+++ b/ExecutorBase/Game/AI/Enums/ShouldNotBeSpellTarget.cs
@@ -1,14 +1,14 @@
-namespace WindBot.Game.AI.Enums
-{
- ///
- /// Cards that are can't be selected as target of spell&trap's effect, or immuned to spell&trap's effect.
- /// So them shouldn't be tried to be selected as target of spell&trap at most times.
- ///
- public enum ShouldNotBeSpellTrapTarget
- {
- ApoqliphortTowers = 27279764,
- ApoqliphortSkybase = 40061558,
- TheLegendaryFishermanIII = 44968687,
- ChaosAncientGearGiant = 51788412
- }
-}
+namespace WindBot.Game.AI.Enums
+{
+ ///
+ /// Cards that are can't be selected as target of spell&trap's effect, or immuned to spell&trap's effect.
+ /// So them shouldn't be tried to be selected as target of spell&trap at most times.
+ ///
+ public enum ShouldNotBeSpellTrapTarget
+ {
+ ApoqliphortTowers = 27279764,
+ ApoqliphortSkybase = 40061558,
+ TheLegendaryFishermanIII = 44968687,
+ ChaosAncientGearGiant = 51788412
+ }
+}
diff --git a/Game/AI/Enums/ShouldNotBeTarget.cs b/ExecutorBase/Game/AI/Enums/ShouldNotBeTarget.cs
similarity index 97%
rename from Game/AI/Enums/ShouldNotBeTarget.cs
rename to ExecutorBase/Game/AI/Enums/ShouldNotBeTarget.cs
index 7adcc587..c3e066d7 100644
--- a/Game/AI/Enums/ShouldNotBeTarget.cs
+++ b/ExecutorBase/Game/AI/Enums/ShouldNotBeTarget.cs
@@ -1,54 +1,54 @@
-namespace WindBot.Game.AI.Enums
-{
- ///
- /// Cards that are can't be selected as target, or immuned to most effect.
- /// So them shouldn't be tried to be selected as target at most times.
- ///
- public enum ShouldNotBeTarget
- {
- DivineSerpentGeh = 82103466,
- ObelisktheTormentor = 10000000,
- TheWingedDragonofRaSphereMode = 10000080,
- TheWingedDragonofRaImmortalPhoenix = 10000090,
- KozmoDarkPlanet = 85991529,
- ZushintheSleepingGiant = 67547370,
- TheLegendaryExodiaIncarnate = 58604027,
- KozmoDarkEclipser = 64063868,
- KozmoDarkDestroyer = 55885348,
- KozmoForerunner = 20849090,
- MajespecterUnicornKirin = 31178212,
- WorldLegacyWorldShield = 55787576,
- KiwiMagicianGirl = 82627406,
- MajespecterFoxKyubi = 94784213,
- MajespecterToadOgama = 645794,
- MajespecterCrowYata = 68395509,
- MajespecterRaccoonBunbuku = 31991800,
- MajespecterCatNekomata = 5506791,
- HazyFlameHydra = 8696773,
- HazyFlameMantikor = 96051150,
- HazyFlameHyppogrif = 31303283,
- HazyFlameCerbereus = 38525760,
- HazyFlameSphynx = 1409474,
- HazyFlamePeryton = 37803172,
- HazyFlameGriffin = 74010769,
- BlueEyesChaosMAXDragon = 55410871,
- BlueEyesChaosDragon = 20654247,
- SupremeKingZARC = 13331639,
- CrimsonNovaTrinitytheDarkCubicLord = 72664875,
- LunalightLeoDancer = 24550676,
- TimaeustheKnightofDestiny = 53315891,
- DantePilgrimoftheBurningAbyss = 18386170,
- AncientGearHowitzer = 87182127,
- InvokedCocytus = 85908279,
- LyriluscIndependentNightingale = 76815942,
- FlowerCardianLightshower = 42291297,
- YaziEviloftheYangZing = 43202238,
- RaidraptorUltimateFalcon = 86221741,
- DisdainfulBirdofParadise = 27240101,
- DarkestDiabolosLordOfTheLair = 50383626,
- Blackwing_FullArmoredWing = 54082269,
- DragunofRedEyes = 37818794,
- RedEyesBDragon = 74677422, // sometimes the name of DragunofRedEyes will be changed to RedEyesBDragon
- TheArrivalCyberseIgnister = 11738489
- }
-}
+namespace WindBot.Game.AI.Enums
+{
+ ///
+ /// Cards that are can't be selected as target, or immuned to most effect.
+ /// So them shouldn't be tried to be selected as target at most times.
+ ///
+ public enum ShouldNotBeTarget
+ {
+ DivineSerpentGeh = 82103466,
+ ObelisktheTormentor = 10000000,
+ TheWingedDragonofRaSphereMode = 10000080,
+ TheWingedDragonofRaImmortalPhoenix = 10000090,
+ KozmoDarkPlanet = 85991529,
+ ZushintheSleepingGiant = 67547370,
+ TheLegendaryExodiaIncarnate = 58604027,
+ KozmoDarkEclipser = 64063868,
+ KozmoDarkDestroyer = 55885348,
+ KozmoForerunner = 20849090,
+ MajespecterUnicornKirin = 31178212,
+ WorldLegacyWorldShield = 55787576,
+ KiwiMagicianGirl = 82627406,
+ MajespecterFoxKyubi = 94784213,
+ MajespecterToadOgama = 645794,
+ MajespecterCrowYata = 68395509,
+ MajespecterRaccoonBunbuku = 31991800,
+ MajespecterCatNekomata = 5506791,
+ HazyFlameHydra = 8696773,
+ HazyFlameMantikor = 96051150,
+ HazyFlameHyppogrif = 31303283,
+ HazyFlameCerbereus = 38525760,
+ HazyFlameSphynx = 1409474,
+ HazyFlamePeryton = 37803172,
+ HazyFlameGriffin = 74010769,
+ BlueEyesChaosMAXDragon = 55410871,
+ BlueEyesChaosDragon = 20654247,
+ SupremeKingZARC = 13331639,
+ CrimsonNovaTrinitytheDarkCubicLord = 72664875,
+ LunalightLeoDancer = 24550676,
+ TimaeustheKnightofDestiny = 53315891,
+ DantePilgrimoftheBurningAbyss = 18386170,
+ AncientGearHowitzer = 87182127,
+ InvokedCocytus = 85908279,
+ LyriluscIndependentNightingale = 76815942,
+ FlowerCardianLightshower = 42291297,
+ YaziEviloftheYangZing = 43202238,
+ RaidraptorUltimateFalcon = 86221741,
+ DisdainfulBirdofParadise = 27240101,
+ DarkestDiabolosLordOfTheLair = 50383626,
+ Blackwing_FullArmoredWing = 54082269,
+ DragunofRedEyes = 37818794,
+ RedEyesBDragon = 74677422, // sometimes the name of DragunofRedEyes will be changed to RedEyesBDragon
+ TheArrivalCyberseIgnister = 11738489
+ }
+}
diff --git a/Game/AI/Executor.cs b/ExecutorBase/Game/AI/Executor.cs
similarity index 95%
rename from Game/AI/Executor.cs
rename to ExecutorBase/Game/AI/Executor.cs
index cc9f7774..7b8b3a6f 100644
--- a/Game/AI/Executor.cs
+++ b/ExecutorBase/Game/AI/Executor.cs
@@ -1,248 +1,251 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using YGOSharp.OCGWrapper.Enums;
-using WindBot;
-using WindBot.Game;
-using WindBot.Game.AI;
-
-namespace WindBot.Game.AI
-{
- public abstract class Executor
- {
- public string Deck { get; set; }
- public Duel Duel { get; private set; }
- public IList Executors { get; private set; }
- public GameAI AI { get; private set; }
- public AIUtil Util { get; private set; }
-
- protected MainPhase Main { get; private set; }
- protected BattlePhase Battle { get; private set; }
-
- protected ExecutorType Type { get; private set; }
- protected ClientCard Card { get; private set; }
- protected int ActivateDescription { get; private set; }
-
- protected ClientField Bot { get; private set; }
- protected ClientField Enemy { get; private set; }
-
- protected Executor(GameAI ai, Duel duel)
- {
- Duel = duel;
- AI = ai;
- Util = new AIUtil(duel);
- Executors = new List();
-
- Bot = Duel.Fields[0];
- Enemy = Duel.Fields[1];
- }
-
- public virtual int OnRockPaperScissors()
- {
- return Program.Rand.Next(1, 4);
- }
-
- public virtual bool OnSelectHand()
- {
- return Program.Rand.Next(2) > 0;
- }
-
- ///
- /// Called when the AI has to decide if it should attack
- ///
- /// List of monsters that can attcack.
- /// List of monsters of enemy.
- /// A new BattlePhaseAction containing the action to do.
- public virtual BattlePhaseAction OnBattle(IList attackers, IList defenders)
- {
- // For overriding
- return null;
- }
-
- ///
- /// Called when the AI has to decide which card to attack first
- ///
- /// List of monsters that can attcack.
- /// List of monsters of enemy.
- /// The card to attack first.
- public virtual ClientCard OnSelectAttacker(IList attackers, IList defenders)
- {
- // For overriding
- return null;
- }
-
- public virtual BattlePhaseAction OnSelectAttackTarget(ClientCard attacker, IList defenders)
- {
- // Overrided in DefalultExecutor
- return null;
- }
-
- public virtual bool OnPreBattleBetween(ClientCard attacker, ClientCard defender)
- {
- // Overrided in DefalultExecutor
- return true;
- }
-
- public virtual void OnChaining(int player, ClientCard card)
- {
- // For overriding
- }
-
- public virtual void OnChainEnd()
- {
- // For overriding
- }
- public virtual void OnNewPhase()
- {
- // Some AI need do something on new phase
- }
- public virtual void OnNewTurn()
- {
- // Some AI need do something on new turn
- }
-
- public virtual void OnDraw(int player)
- {
- // Some AI need do something on draw
- }
-
- public virtual IList OnSelectCard(IList cards, int min, int max, int hint, bool cancelable)
- {
- // For overriding
- return null;
- }
-
- public virtual IList OnSelectSum(IList cards, int sum, int min, int max, int hint, bool mode)
- {
- // For overriding
- return null;
- }
-
- public virtual IList OnSelectFusionMaterial(IList cards, int min, int max)
- {
- // For overriding
- return null;
- }
-
- public virtual IList OnSelectSynchroMaterial(IList cards, int sum, int min, int max)
- {
- // For overriding
- return null;
- }
-
- public virtual IList OnSelectXyzMaterial(IList cards, int min, int max)
- {
- // For overriding
- return null;
- }
-
- public virtual IList OnSelectLinkMaterial(IList cards, int min, int max)
- {
- // For overriding
- return null;
- }
-
- public virtual IList OnSelectRitualTribute(IList cards, int sum, int min, int max)
- {
- // For overriding
- return null;
- }
-
- public virtual IList OnSelectPendulumSummon(IList cards, int max)
- {
- // For overriding
- return null;
- }
-
- public virtual IList OnCardSorting(IList cards)
- {
- // For overriding
- return null;
- }
-
- 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 CardPosition OnSelectPosition(int cardId, IList positions)
- {
- // Overrided in DefalultExecutor
- return 0;
- }
-
- public virtual bool OnSelectBattleReplay()
- {
- // Overrided in DefalultExecutor
- return false;
- }
-
- public void SetMain(MainPhase main)
- {
- Main = main;
- }
-
- public void SetBattle(BattlePhase battle)
- {
- Battle = battle;
- }
-
- ///
- /// Set global variables Type, Card, ActivateDescription for Executor
- ///
- public void SetCard(ExecutorType type, ClientCard card, int description)
- {
- Type = type;
- Card = card;
- ActivateDescription = description;
- }
-
- ///
- /// Do the action for the card if func return true.
- ///
- public void AddExecutor(ExecutorType type, int cardId, Func func)
- {
- Executors.Add(new CardExecutor(type, cardId, func));
- }
-
- ///
- /// Do the action for the card if available.
- ///
- public void AddExecutor(ExecutorType type, int cardId)
- {
- Executors.Add(new CardExecutor(type, cardId, null));
- }
-
- ///
- /// Do the action for every card if func return true.
- ///
- public void AddExecutor(ExecutorType type, Func func)
- {
- Executors.Add(new CardExecutor(type, -1, func));
- }
-
- ///
- /// Do the action for every card if no other Executor is added to it.
- ///
- public void AddExecutor(ExecutorType type)
- {
- Executors.Add(new CardExecutor(type, -1, DefaultNoExecutor));
- }
-
- private bool DefaultNoExecutor()
- {
- return Executors.All(exec => exec.Type != Type || exec.CardId != Card.Id);
- }
- }
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using YGOSharp.OCGWrapper.Enums;
+using WindBot;
+using WindBot.Game;
+using WindBot.Game.AI;
+
+namespace WindBot.Game.AI
+{
+ public abstract class Executor
+ {
+ public string Deck { get; set; }
+ public Duel Duel { get; private set; }
+ public IList Executors { get; private set; }
+ public GameAI AI { get; private set; }
+ public AIUtil Util { get; private set; }
+
+ protected MainPhase Main { get; private set; }
+ protected BattlePhase Battle { get; private set; }
+
+ protected ExecutorType Type { get; private set; }
+ protected ClientCard Card { get; private set; }
+ protected int ActivateDescription { get; private set; }
+
+ protected ClientField Bot { get; private set; }
+ protected ClientField Enemy { get; private set; }
+
+ public Random Rand;
+
+ protected Executor(GameAI ai, Duel duel)
+ {
+ Rand = new Random();
+ Duel = duel;
+ AI = ai;
+ Util = new AIUtil(duel);
+ Executors = new List();
+
+ Bot = Duel.Fields[0];
+ Enemy = Duel.Fields[1];
+ }
+
+ public virtual int OnRockPaperScissors()
+ {
+ return Rand.Next(1, 4);
+ }
+
+ public virtual bool OnSelectHand()
+ {
+ return Rand.Next(2) > 0;
+ }
+
+ ///
+ /// Called when the AI has to decide if it should attack
+ ///
+ /// List of monsters that can attcack.
+ /// List of monsters of enemy.
+ /// A new BattlePhaseAction containing the action to do.
+ public virtual BattlePhaseAction OnBattle(IList attackers, IList defenders)
+ {
+ // For overriding
+ return null;
+ }
+
+ ///
+ /// Called when the AI has to decide which card to attack first
+ ///
+ /// List of monsters that can attcack.
+ /// List of monsters of enemy.
+ /// The card to attack first.
+ public virtual ClientCard OnSelectAttacker(IList attackers, IList defenders)
+ {
+ // For overriding
+ return null;
+ }
+
+ public virtual BattlePhaseAction OnSelectAttackTarget(ClientCard attacker, IList defenders)
+ {
+ // Overrided in DefalultExecutor
+ return null;
+ }
+
+ public virtual bool OnPreBattleBetween(ClientCard attacker, ClientCard defender)
+ {
+ // Overrided in DefalultExecutor
+ return true;
+ }
+
+ public virtual void OnChaining(int player, ClientCard card)
+ {
+ // For overriding
+ }
+
+ public virtual void OnChainEnd()
+ {
+ // For overriding
+ }
+ public virtual void OnNewPhase()
+ {
+ // Some AI need do something on new phase
+ }
+ public virtual void OnNewTurn()
+ {
+ // Some AI need do something on new turn
+ }
+
+ public virtual void OnDraw(int player)
+ {
+ // Some AI need do something on draw
+ }
+
+ public virtual IList OnSelectCard(IList cards, int min, int max, int hint, bool cancelable)
+ {
+ // For overriding
+ return null;
+ }
+
+ public virtual IList OnSelectSum(IList cards, int sum, int min, int max, int hint, bool mode)
+ {
+ // For overriding
+ return null;
+ }
+
+ public virtual IList OnSelectFusionMaterial(IList cards, int min, int max)
+ {
+ // For overriding
+ return null;
+ }
+
+ public virtual IList OnSelectSynchroMaterial(IList cards, int sum, int min, int max)
+ {
+ // For overriding
+ return null;
+ }
+
+ public virtual IList OnSelectXyzMaterial(IList cards, int min, int max)
+ {
+ // For overriding
+ return null;
+ }
+
+ public virtual IList OnSelectLinkMaterial(IList cards, int min, int max)
+ {
+ // For overriding
+ return null;
+ }
+
+ public virtual IList OnSelectRitualTribute(IList cards, int sum, int min, int max)
+ {
+ // For overriding
+ return null;
+ }
+
+ public virtual IList OnSelectPendulumSummon(IList cards, int max)
+ {
+ // For overriding
+ return null;
+ }
+
+ public virtual IList OnCardSorting(IList cards)
+ {
+ // For overriding
+ return null;
+ }
+
+ 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 CardPosition OnSelectPosition(int cardId, IList positions)
+ {
+ // Overrided in DefalultExecutor
+ return 0;
+ }
+
+ public virtual bool OnSelectBattleReplay()
+ {
+ // Overrided in DefalultExecutor
+ return false;
+ }
+
+ public void SetMain(MainPhase main)
+ {
+ Main = main;
+ }
+
+ public void SetBattle(BattlePhase battle)
+ {
+ Battle = battle;
+ }
+
+ ///
+ /// Set global variables Type, Card, ActivateDescription for Executor
+ ///
+ public void SetCard(ExecutorType type, ClientCard card, int description)
+ {
+ Type = type;
+ Card = card;
+ ActivateDescription = description;
+ }
+
+ ///
+ /// Do the action for the card if func return true.
+ ///
+ public void AddExecutor(ExecutorType type, int cardId, Func func)
+ {
+ Executors.Add(new CardExecutor(type, cardId, func));
+ }
+
+ ///
+ /// Do the action for the card if available.
+ ///
+ public void AddExecutor(ExecutorType type, int cardId)
+ {
+ Executors.Add(new CardExecutor(type, cardId, null));
+ }
+
+ ///
+ /// Do the action for every card if func return true.
+ ///
+ public void AddExecutor(ExecutorType type, Func func)
+ {
+ Executors.Add(new CardExecutor(type, -1, func));
+ }
+
+ ///
+ /// Do the action for every card if no other Executor is added to it.
+ ///
+ public void AddExecutor(ExecutorType type)
+ {
+ Executors.Add(new CardExecutor(type, -1, DefaultNoExecutor));
+ }
+
+ private bool DefaultNoExecutor()
+ {
+ return Executors.All(exec => exec.Type != Type || exec.CardId != Card.Id);
+ }
+ }
}
\ No newline at end of file
diff --git a/Game/AI/ExecutorType.cs b/ExecutorBase/Game/AI/ExecutorType.cs
similarity index 94%
rename from Game/AI/ExecutorType.cs
rename to ExecutorBase/Game/AI/ExecutorType.cs
index 47a557d3..dc4b8083 100644
--- a/Game/AI/ExecutorType.cs
+++ b/ExecutorBase/Game/AI/ExecutorType.cs
@@ -1,16 +1,16 @@
-namespace WindBot.Game.AI
-{
- public enum ExecutorType
- {
- Summon,
- SpSummon,
- Repos,
- MonsterSet,
- SpellSet,
- Activate,
- SummonOrSet,
- GoToBattlePhase,
- GoToMainPhase2,
- GoToEndPhase
- }
+namespace WindBot.Game.AI
+{
+ public enum ExecutorType
+ {
+ Summon,
+ SpSummon,
+ Repos,
+ MonsterSet,
+ SpellSet,
+ Activate,
+ SummonOrSet,
+ GoToBattlePhase,
+ GoToMainPhase2,
+ GoToEndPhase
+ }
}
\ No newline at end of file
diff --git a/Game/AI/Zones.cs b/ExecutorBase/Game/AI/Zones.cs
similarity index 95%
rename from Game/AI/Zones.cs
rename to ExecutorBase/Game/AI/Zones.cs
index 05944de4..f4721c0b 100644
--- a/Game/AI/Zones.cs
+++ b/ExecutorBase/Game/AI/Zones.cs
@@ -1,24 +1,24 @@
-namespace WindBot.Game.AI
-{
- public static class Zones
- {
- public const int z0 = 0x1,
- z1 = 0x2,
- z2 = 0x4,
- z3 = 0x8,
- z4 = 0x10,
- z5 = 0x20,
- z6 = 0x40,
-
- MonsterZones = 0x7f,
- MainMonsterZones = 0x1f,
- ExtraMonsterZones = 0x60,
-
- SpellZones = 0x1f,
-
- PendulumZones = 0x3,
-
- LinkedZones = 0x10000,
- NotLinkedZones = 0x20000;
- }
+namespace WindBot.Game.AI
+{
+ public static class Zones
+ {
+ public const int z0 = 0x1,
+ z1 = 0x2,
+ z2 = 0x4,
+ z3 = 0x8,
+ z4 = 0x10,
+ z5 = 0x20,
+ z6 = 0x40,
+
+ MonsterZones = 0x7f,
+ MainMonsterZones = 0x1f,
+ ExtraMonsterZones = 0x60,
+
+ SpellZones = 0x1f,
+
+ PendulumZones = 0x3,
+
+ LinkedZones = 0x10000,
+ NotLinkedZones = 0x20000;
+ }
}
\ No newline at end of file
diff --git a/Game/BattlePhase.cs b/ExecutorBase/Game/BattlePhase.cs
similarity index 96%
rename from Game/BattlePhase.cs
rename to ExecutorBase/Game/BattlePhase.cs
index e895a315..75139c6b 100644
--- a/Game/BattlePhase.cs
+++ b/ExecutorBase/Game/BattlePhase.cs
@@ -1,20 +1,20 @@
-using System.Collections.Generic;
-
-namespace WindBot.Game
-{
- public class BattlePhase
- {
- public IList AttackableCards { get; private set; }
- public IList ActivableCards { get; private set; }
- public IList ActivableDescs { get; private set; }
- public bool CanMainPhaseTwo { get; set; }
- public bool CanEndPhase { get; set; }
-
- public BattlePhase()
- {
- AttackableCards = new List();
- ActivableCards = new List();
- ActivableDescs = new List();
- }
- }
+using System.Collections.Generic;
+
+namespace WindBot.Game
+{
+ public class BattlePhase
+ {
+ public IList AttackableCards { get; private set; }
+ public IList ActivableCards { get; private set; }
+ public IList ActivableDescs { get; private set; }
+ public bool CanMainPhaseTwo { get; set; }
+ public bool CanEndPhase { get; set; }
+
+ public BattlePhase()
+ {
+ AttackableCards = new List();
+ ActivableCards = new List();
+ ActivableDescs = new List();
+ }
+ }
}
\ No newline at end of file
diff --git a/Game/BattlePhaseAction.cs b/ExecutorBase/Game/BattlePhaseAction.cs
similarity index 95%
rename from Game/BattlePhaseAction.cs
rename to ExecutorBase/Game/BattlePhaseAction.cs
index 3238a22b..f11d148b 100644
--- a/Game/BattlePhaseAction.cs
+++ b/ExecutorBase/Game/BattlePhaseAction.cs
@@ -1,33 +1,33 @@
-namespace WindBot.Game
-{
- public class BattlePhaseAction
- {
- public enum BattleAction
- {
- Activate = 0,
- Attack = 1,
- ToMainPhaseTwo = 2,
- ToEndPhase = 3
- }
-
- public BattleAction Action { get; private set; }
- public int Index { get; private set; }
-
- public BattlePhaseAction(BattleAction action)
- {
- Action = action;
- Index = 0;
- }
-
- public BattlePhaseAction(BattleAction action, int[] indexes)
- {
- Action = action;
- Index = indexes[(int)action];
- }
-
- public int ToValue()
- {
- return (Index << 16) + (int)Action;
- }
- }
+namespace WindBot.Game
+{
+ public class BattlePhaseAction
+ {
+ public enum BattleAction
+ {
+ Activate = 0,
+ Attack = 1,
+ ToMainPhaseTwo = 2,
+ ToEndPhase = 3
+ }
+
+ public BattleAction Action { get; private set; }
+ public int Index { get; private set; }
+
+ public BattlePhaseAction(BattleAction action)
+ {
+ Action = action;
+ Index = 0;
+ }
+
+ public BattlePhaseAction(BattleAction action, int[] indexes)
+ {
+ Action = action;
+ Index = indexes[(int)action];
+ }
+
+ public int ToValue()
+ {
+ return (Index << 16) + (int)Action;
+ }
+ }
}
\ No newline at end of file
diff --git a/Game/ClientCard.cs b/ExecutorBase/Game/ClientCard.cs
similarity index 97%
rename from Game/ClientCard.cs
rename to ExecutorBase/Game/ClientCard.cs
index 4a4ece3c..ba1e0e2e 100644
--- a/Game/ClientCard.cs
+++ b/ExecutorBase/Game/ClientCard.cs
@@ -1,374 +1,374 @@
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using YGOSharp.OCGWrapper;
-using YGOSharp.OCGWrapper.Enums;
-
-namespace WindBot.Game
-{
- public class ClientCard
- {
- public int Id { get; private set; }
- public NamedCard Data { get; private set; }
- public string Name { get; private set; }
-
- public int Position { get; set; }
- public int Sequence { get; set; }
- public CardLocation Location { get; set; }
- public int Alias { get; private set; }
- public int Level { get; private set; }
- public int Rank { get; private set; }
- public int Type { get; private set; }
- public int Attribute { get; private set; }
- public int Race { get; private set; }
- public int Attack { get; private set; }
- public int Defense { get; private set; }
- public int LScale { get; private set; }
- public int RScale { get; private set; }
- public int LinkCount { get; private set; }
- public int LinkMarker { get; private set; }
- public int BaseAttack { get; private set; }
- public int BaseDefense { get; private set; }
- public int RealPower { get; set; }
- public List Overlays { get; private set; }
- public int Owner { get; private set; }
- public int Controller { get; private set; }
- public int Disabled { get; private set; }
- public int ProcCompleted { get; private set; }
- public int SelectSeq { get; set; }
- public int OpParam1 { get; set; }
- public int OpParam2 { get; set; }
-
- public List EquipCards { get; set; }
- public ClientCard EquipTarget;
- public List OwnTargets { get; set; }
- public List TargetCards { get; set; }
-
- public bool CanDirectAttack { get; set; }
- public bool ShouldDirectAttack { get; set; }
- public bool Attacked { get; set; }
- public bool IsLastAttacker { get; set; }
- public bool IsSpecialSummoned { get; set; }
-
- public int[] ActionIndex { get; set; }
- public IDictionary ActionActivateIndex { get; private set; }
-
- public ClientCard(int id, CardLocation loc, int sequence)
- : this(id, loc, -1 , 0)
- {
- }
-
- public ClientCard(int id, CardLocation loc, int sequence, int position)
- {
- SetId(id);
- Sequence = sequence;
- Position = position;
- Overlays = new List();
- EquipCards = new List();
- OwnTargets = new List();
- TargetCards = new List();
- ActionIndex = new int[16];
- ActionActivateIndex = new Dictionary();
- Location = loc;
- }
-
- public void SetId(int id)
- {
- if (Id == id) return;
- Id = id;
- Data = NamedCard.Get(Id);
- if (Data != null)
- {
- Name = Data.Name;
- if (Data.Alias != 0)
- Alias = Data.Alias;
- }
- }
-
- public void Update(BinaryReader packet, Duel duel)
- {
- int flag = packet.ReadInt32();
- if ((flag & (int)Query.Code) != 0)
- SetId(packet.ReadInt32());
- if ((flag & (int)Query.Position) != 0)
- {
- Controller = duel.GetLocalPlayer(packet.ReadByte());
- Location = (CardLocation)packet.ReadByte();
- Sequence = packet.ReadByte();
- Position = packet.ReadByte();
- }
- if ((flag & (int)Query.Alias) != 0)
- Alias = packet.ReadInt32();
- if ((flag & (int)Query.Type) != 0)
- Type = packet.ReadInt32();
- if ((flag & (int)Query.Level) != 0)
- Level = packet.ReadInt32();
- if ((flag & (int)Query.Rank) != 0)
- Rank = packet.ReadInt32();
- if ((flag & (int)Query.Attribute) != 0)
- Attribute = packet.ReadInt32();
- if ((flag & (int)Query.Race) != 0)
- Race = packet.ReadInt32();
- if ((flag & (int)Query.Attack) != 0)
- Attack = packet.ReadInt32();
- if ((flag & (int)Query.Defence) != 0)
- Defense = packet.ReadInt32();
- if ((flag & (int)Query.BaseAttack) != 0)
- BaseAttack = packet.ReadInt32();
- if ((flag & (int)Query.BaseDefence) != 0)
- BaseDefense = packet.ReadInt32();
- if ((flag & (int)Query.Reason) != 0)
- packet.ReadInt32();
- if ((flag & (int)Query.ReasonCard) != 0)
- packet.ReadInt32(); // Int8 * 4
- if ((flag & (int)Query.EquipCard) != 0)
- packet.ReadInt32(); // Int8 * 4
- if ((flag & (int)Query.TargetCard) != 0)
- {
- int count = packet.ReadInt32();
- for (int i = 0; i < count; ++i)
- packet.ReadInt32(); // Int8 * 4
- }
- if ((flag & (int)Query.OverlayCard) != 0)
- {
- Overlays.Clear();
- int count = packet.ReadInt32();
- for (int i = 0; i < count; ++i)
- Overlays.Add(packet.ReadInt32());
- }
- if ((flag & (int)Query.Counters) != 0)
- {
- int count = packet.ReadInt32();
- for (int i = 0; i < count; ++i)
- packet.ReadInt32(); // Int16 * 2
- }
- if ((flag & (int)Query.Owner) != 0)
- Owner = duel.GetLocalPlayer(packet.ReadInt32());
- if ((flag & (int)Query.Status) != 0) {
- int status = packet.ReadInt32();
- const int STATUS_DISABLED = 0x0001;
- const int STATUS_PROC_COMPLETE = 0x0008;
- Disabled = status & STATUS_DISABLED;
- ProcCompleted = status & STATUS_PROC_COMPLETE;
- }
- if ((flag & (int)Query.LScale) != 0)
- LScale = packet.ReadInt32();
- if ((flag & (int)Query.RScale) != 0)
- RScale = packet.ReadInt32();
- if ((flag & (int)Query.Link) != 0)
- {
- LinkCount = packet.ReadInt32();
- LinkMarker = packet.ReadInt32();
- }
- }
-
- public void ClearCardTargets()
- {
- foreach (ClientCard card in TargetCards)
- {
- card.OwnTargets.Remove(this);
- }
- foreach (ClientCard card in OwnTargets)
- {
- card.TargetCards.Remove(this);
- }
- OwnTargets.Clear();
- TargetCards.Clear();
- }
-
- public bool HasLinkMarker(int dir)
- {
- return (LinkMarker & dir) != 0;
- }
-
- public bool HasLinkMarker(CardLinkMarker dir)
- {
- return (LinkMarker & (int)dir) != 0;
- }
-
- public int GetLinkedZones()
- {
- if (!HasType(CardType.Link) || Location != CardLocation.MonsterZone)
- return 0;
- int zones = 0;
- if (Sequence > 0 && Sequence <= 4 && HasLinkMarker(CardLinkMarker.Left))
- zones |= 1 << (Sequence - 1);
- if (Sequence <= 3 && HasLinkMarker(CardLinkMarker.Right))
- zones |= 1 << (Sequence + 1);
- if (Sequence == 0 && HasLinkMarker(CardLinkMarker.TopRight)
- || Sequence == 1 && HasLinkMarker(CardLinkMarker.Top)
- || Sequence == 2 && HasLinkMarker(CardLinkMarker.TopLeft))
- zones |= (1 << 5) | (1 << (16 + 6));
- if (Sequence == 2 && HasLinkMarker(CardLinkMarker.TopRight)
- || Sequence == 3 && HasLinkMarker(CardLinkMarker.Top)
- || Sequence == 4 && HasLinkMarker(CardLinkMarker.TopLeft))
- zones |= (1 << 6) | (1 << (16 + 5));
- if (Sequence == 5)
- {
- if (HasLinkMarker(CardLinkMarker.BottomLeft))
- zones |= 1 << 0;
- if (HasLinkMarker(CardLinkMarker.Bottom))
- zones |= 1 << 1;
- if (HasLinkMarker(CardLinkMarker.BottomRight))
- zones |= 1 << 2;
- if (HasLinkMarker(CardLinkMarker.TopLeft))
- zones |= 1 << (16 + 4);
- if (HasLinkMarker(CardLinkMarker.Top))
- zones |= 1 << (16 + 3);
- if (HasLinkMarker(CardLinkMarker.TopRight))
- zones |= 1 << (16 + 2);
- }
- if (Sequence == 6)
- {
- if (HasLinkMarker(CardLinkMarker.BottomLeft))
- zones |= 1 << 2;
- if (HasLinkMarker(CardLinkMarker.Bottom))
- zones |= 1 << 3;
- if (HasLinkMarker(CardLinkMarker.BottomRight))
- zones |= 1 << 4;
- if (HasLinkMarker(CardLinkMarker.TopLeft))
- zones |= 1 << (16 + 2);
- if (HasLinkMarker(CardLinkMarker.Top))
- zones |= 1 << (16 + 1);
- if (HasLinkMarker(CardLinkMarker.TopRight))
- zones |= 1 << (16 + 0);
- }
- return zones;
- }
-
- public bool HasType(CardType type)
- {
- return (Type & (int)type) != 0;
- }
-
- public bool HasPosition(CardPosition position)
- {
- return (Position & (int)position) != 0;
- }
-
- public bool HasAttribute(CardAttribute attribute)
- {
- return (Attribute & (int)attribute) != 0;
- }
-
- public bool HasRace(CardRace race)
- {
- return (Race & (int)race) != 0;
- }
-
- public bool HasSetcode(int setcode)
- {
- if (Data == null) return false;
- long setcodes = Data.Setcode;
- int settype = setcode & 0xfff;
- int setsubtype = setcode & 0xf000;
- while (setcodes > 0)
- {
- long check_setcode = setcodes & 0xffff;
- setcodes >>= 16;
- if ((check_setcode & 0xfff) == settype && (check_setcode & 0xf000 & setsubtype) == setsubtype) return true;
- }
- return false;
- }
-
- public bool IsMonster()
- {
- return HasType(CardType.Monster);
- }
-
- public bool IsTuner()
- {
- return HasType(CardType.Tuner);
- }
-
- public bool IsSpell()
- {
- return HasType(CardType.Spell);
- }
-
- public bool IsTrap()
- {
- return HasType(CardType.Trap);
- }
-
- public bool IsExtraCard()
- {
- return HasType(CardType.Fusion) || HasType(CardType.Synchro) || HasType(CardType.Xyz) || HasType(CardType.Link);
- }
-
- public bool IsFaceup()
- {
- return HasPosition(CardPosition.FaceUp);
- }
-
- public bool IsFacedown()
- {
- return HasPosition(CardPosition.FaceDown);
- }
-
- public bool IsAttack()
- {
- return HasPosition(CardPosition.Attack);
- }
-
- public bool IsDefense()
- {
- return HasPosition(CardPosition.Defence);
- }
-
- public bool IsDisabled()
- {
- return Disabled != 0;
- }
-
- public bool IsCanRevive()
- {
- return ProcCompleted != 0 || !(IsExtraCard() || HasType(CardType.Ritual) || HasType(CardType.SpSummon));
- }
-
- public bool IsCode(int id)
- {
- return Id == id || Alias != 0 && Alias == id;
- }
-
- public bool IsCode(IList ids)
- {
- return ids.Contains(Id) || Alias != 0 && ids.Contains(Alias);
- }
-
- public bool IsCode(params int[] ids)
- {
- return ids.Contains(Id) || Alias != 0 && ids.Contains(Alias);
- }
-
- public bool IsOriginalCode(int id)
- {
- return Id == id || Alias - Id < 10 && Alias == id;
- }
-
- public bool HasXyzMaterial()
- {
- return Overlays.Count > 0;
- }
-
- public bool HasXyzMaterial(int count)
- {
- return Overlays.Count >= count;
- }
-
- public bool HasXyzMaterial(int count, int cardid)
- {
- return Overlays.Count >= count && Overlays.Contains(cardid);
- }
-
- public int GetDefensePower()
- {
- return IsAttack() ? Attack : Defense;
- }
-
- public bool Equals(ClientCard card)
- {
- return ReferenceEquals(this, card);
- }
- }
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using YGOSharp.OCGWrapper;
+using YGOSharp.OCGWrapper.Enums;
+
+namespace WindBot.Game
+{
+ public class ClientCard
+ {
+ public int Id { get; private set; }
+ public NamedCard Data { get; private set; }
+ public string Name { get; private set; }
+
+ public int Position { get; set; }
+ public int Sequence { get; set; }
+ public CardLocation Location { get; set; }
+ public int Alias { get; private set; }
+ public int Level { get; private set; }
+ public int Rank { get; private set; }
+ public int Type { get; private set; }
+ public int Attribute { get; private set; }
+ public int Race { get; private set; }
+ public int Attack { get; private set; }
+ public int Defense { get; private set; }
+ public int LScale { get; private set; }
+ public int RScale { get; private set; }
+ public int LinkCount { get; private set; }
+ public int LinkMarker { get; private set; }
+ public int BaseAttack { get; private set; }
+ public int BaseDefense { get; private set; }
+ public int RealPower { get; set; }
+ public List Overlays { get; private set; }
+ public int Owner { get; private set; }
+ public int Controller { get; private set; }
+ public int Disabled { get; private set; }
+ public int ProcCompleted { get; private set; }
+ public int SelectSeq { get; set; }
+ public int OpParam1 { get; set; }
+ public int OpParam2 { get; set; }
+
+ public List EquipCards { get; set; }
+ public ClientCard EquipTarget;
+ public List OwnTargets { get; set; }
+ public List TargetCards { get; set; }
+
+ public bool CanDirectAttack { get; set; }
+ public bool ShouldDirectAttack { get; set; }
+ public bool Attacked { get; set; }
+ public bool IsLastAttacker { get; set; }
+ public bool IsSpecialSummoned { get; set; }
+
+ public int[] ActionIndex { get; set; }
+ public IDictionary ActionActivateIndex { get; private set; }
+
+ public ClientCard(int id, CardLocation loc, int sequence)
+ : this(id, loc, -1 , 0)
+ {
+ }
+
+ public ClientCard(int id, CardLocation loc, int sequence, int position)
+ {
+ SetId(id);
+ Sequence = sequence;
+ Position = position;
+ Overlays = new List();
+ EquipCards = new List();
+ OwnTargets = new List();
+ TargetCards = new List();
+ ActionIndex = new int[16];
+ ActionActivateIndex = new Dictionary();
+ Location = loc;
+ }
+
+ public void SetId(int id)
+ {
+ if (Id == id) return;
+ Id = id;
+ Data = NamedCard.Get(Id);
+ if (Data != null)
+ {
+ Name = Data.Name;
+ if (Data.Alias != 0)
+ Alias = Data.Alias;
+ }
+ }
+
+ public void Update(BinaryReader packet, Duel duel)
+ {
+ int flag = packet.ReadInt32();
+ if ((flag & (int)Query.Code) != 0)
+ SetId(packet.ReadInt32());
+ if ((flag & (int)Query.Position) != 0)
+ {
+ Controller = duel.GetLocalPlayer(packet.ReadByte());
+ Location = (CardLocation)packet.ReadByte();
+ Sequence = packet.ReadByte();
+ Position = packet.ReadByte();
+ }
+ if ((flag & (int)Query.Alias) != 0)
+ Alias = packet.ReadInt32();
+ if ((flag & (int)Query.Type) != 0)
+ Type = packet.ReadInt32();
+ if ((flag & (int)Query.Level) != 0)
+ Level = packet.ReadInt32();
+ if ((flag & (int)Query.Rank) != 0)
+ Rank = packet.ReadInt32();
+ if ((flag & (int)Query.Attribute) != 0)
+ Attribute = packet.ReadInt32();
+ if ((flag & (int)Query.Race) != 0)
+ Race = packet.ReadInt32();
+ if ((flag & (int)Query.Attack) != 0)
+ Attack = packet.ReadInt32();
+ if ((flag & (int)Query.Defence) != 0)
+ Defense = packet.ReadInt32();
+ if ((flag & (int)Query.BaseAttack) != 0)
+ BaseAttack = packet.ReadInt32();
+ if ((flag & (int)Query.BaseDefence) != 0)
+ BaseDefense = packet.ReadInt32();
+ if ((flag & (int)Query.Reason) != 0)
+ packet.ReadInt32();
+ if ((flag & (int)Query.ReasonCard) != 0)
+ packet.ReadInt32(); // Int8 * 4
+ if ((flag & (int)Query.EquipCard) != 0)
+ packet.ReadInt32(); // Int8 * 4
+ if ((flag & (int)Query.TargetCard) != 0)
+ {
+ int count = packet.ReadInt32();
+ for (int i = 0; i < count; ++i)
+ packet.ReadInt32(); // Int8 * 4
+ }
+ if ((flag & (int)Query.OverlayCard) != 0)
+ {
+ Overlays.Clear();
+ int count = packet.ReadInt32();
+ for (int i = 0; i < count; ++i)
+ Overlays.Add(packet.ReadInt32());
+ }
+ if ((flag & (int)Query.Counters) != 0)
+ {
+ int count = packet.ReadInt32();
+ for (int i = 0; i < count; ++i)
+ packet.ReadInt32(); // Int16 * 2
+ }
+ if ((flag & (int)Query.Owner) != 0)
+ Owner = duel.GetLocalPlayer(packet.ReadInt32());
+ if ((flag & (int)Query.Status) != 0) {
+ int status = packet.ReadInt32();
+ const int STATUS_DISABLED = 0x0001;
+ const int STATUS_PROC_COMPLETE = 0x0008;
+ Disabled = status & STATUS_DISABLED;
+ ProcCompleted = status & STATUS_PROC_COMPLETE;
+ }
+ if ((flag & (int)Query.LScale) != 0)
+ LScale = packet.ReadInt32();
+ if ((flag & (int)Query.RScale) != 0)
+ RScale = packet.ReadInt32();
+ if ((flag & (int)Query.Link) != 0)
+ {
+ LinkCount = packet.ReadInt32();
+ LinkMarker = packet.ReadInt32();
+ }
+ }
+
+ public void ClearCardTargets()
+ {
+ foreach (ClientCard card in TargetCards)
+ {
+ card.OwnTargets.Remove(this);
+ }
+ foreach (ClientCard card in OwnTargets)
+ {
+ card.TargetCards.Remove(this);
+ }
+ OwnTargets.Clear();
+ TargetCards.Clear();
+ }
+
+ public bool HasLinkMarker(int dir)
+ {
+ return (LinkMarker & dir) != 0;
+ }
+
+ public bool HasLinkMarker(CardLinkMarker dir)
+ {
+ return (LinkMarker & (int)dir) != 0;
+ }
+
+ public int GetLinkedZones()
+ {
+ if (!HasType(CardType.Link) || Location != CardLocation.MonsterZone)
+ return 0;
+ int zones = 0;
+ if (Sequence > 0 && Sequence <= 4 && HasLinkMarker(CardLinkMarker.Left))
+ zones |= 1 << (Sequence - 1);
+ if (Sequence <= 3 && HasLinkMarker(CardLinkMarker.Right))
+ zones |= 1 << (Sequence + 1);
+ if (Sequence == 0 && HasLinkMarker(CardLinkMarker.TopRight)
+ || Sequence == 1 && HasLinkMarker(CardLinkMarker.Top)
+ || Sequence == 2 && HasLinkMarker(CardLinkMarker.TopLeft))
+ zones |= (1 << 5) | (1 << (16 + 6));
+ if (Sequence == 2 && HasLinkMarker(CardLinkMarker.TopRight)
+ || Sequence == 3 && HasLinkMarker(CardLinkMarker.Top)
+ || Sequence == 4 && HasLinkMarker(CardLinkMarker.TopLeft))
+ zones |= (1 << 6) | (1 << (16 + 5));
+ if (Sequence == 5)
+ {
+ if (HasLinkMarker(CardLinkMarker.BottomLeft))
+ zones |= 1 << 0;
+ if (HasLinkMarker(CardLinkMarker.Bottom))
+ zones |= 1 << 1;
+ if (HasLinkMarker(CardLinkMarker.BottomRight))
+ zones |= 1 << 2;
+ if (HasLinkMarker(CardLinkMarker.TopLeft))
+ zones |= 1 << (16 + 4);
+ if (HasLinkMarker(CardLinkMarker.Top))
+ zones |= 1 << (16 + 3);
+ if (HasLinkMarker(CardLinkMarker.TopRight))
+ zones |= 1 << (16 + 2);
+ }
+ if (Sequence == 6)
+ {
+ if (HasLinkMarker(CardLinkMarker.BottomLeft))
+ zones |= 1 << 2;
+ if (HasLinkMarker(CardLinkMarker.Bottom))
+ zones |= 1 << 3;
+ if (HasLinkMarker(CardLinkMarker.BottomRight))
+ zones |= 1 << 4;
+ if (HasLinkMarker(CardLinkMarker.TopLeft))
+ zones |= 1 << (16 + 2);
+ if (HasLinkMarker(CardLinkMarker.Top))
+ zones |= 1 << (16 + 1);
+ if (HasLinkMarker(CardLinkMarker.TopRight))
+ zones |= 1 << (16 + 0);
+ }
+ return zones;
+ }
+
+ public bool HasType(CardType type)
+ {
+ return (Type & (int)type) != 0;
+ }
+
+ public bool HasPosition(CardPosition position)
+ {
+ return (Position & (int)position) != 0;
+ }
+
+ public bool HasAttribute(CardAttribute attribute)
+ {
+ return (Attribute & (int)attribute) != 0;
+ }
+
+ public bool HasRace(CardRace race)
+ {
+ return (Race & (int)race) != 0;
+ }
+
+ public bool HasSetcode(int setcode)
+ {
+ if (Data == null) return false;
+ long setcodes = Data.Setcode;
+ int settype = setcode & 0xfff;
+ int setsubtype = setcode & 0xf000;
+ while (setcodes > 0)
+ {
+ long check_setcode = setcodes & 0xffff;
+ setcodes >>= 16;
+ if ((check_setcode & 0xfff) == settype && (check_setcode & 0xf000 & setsubtype) == setsubtype) return true;
+ }
+ return false;
+ }
+
+ public bool IsMonster()
+ {
+ return HasType(CardType.Monster);
+ }
+
+ public bool IsTuner()
+ {
+ return HasType(CardType.Tuner);
+ }
+
+ public bool IsSpell()
+ {
+ return HasType(CardType.Spell);
+ }
+
+ public bool IsTrap()
+ {
+ return HasType(CardType.Trap);
+ }
+
+ public bool IsExtraCard()
+ {
+ return HasType(CardType.Fusion) || HasType(CardType.Synchro) || HasType(CardType.Xyz) || HasType(CardType.Link);
+ }
+
+ public bool IsFaceup()
+ {
+ return HasPosition(CardPosition.FaceUp);
+ }
+
+ public bool IsFacedown()
+ {
+ return HasPosition(CardPosition.FaceDown);
+ }
+
+ public bool IsAttack()
+ {
+ return HasPosition(CardPosition.Attack);
+ }
+
+ public bool IsDefense()
+ {
+ return HasPosition(CardPosition.Defence);
+ }
+
+ public bool IsDisabled()
+ {
+ return Disabled != 0;
+ }
+
+ public bool IsCanRevive()
+ {
+ return ProcCompleted != 0 || !(IsExtraCard() || HasType(CardType.Ritual) || HasType(CardType.SpSummon));
+ }
+
+ public bool IsCode(int id)
+ {
+ return Id == id || Alias != 0 && Alias == id;
+ }
+
+ public bool IsCode(IList ids)
+ {
+ return ids.Contains(Id) || Alias != 0 && ids.Contains(Alias);
+ }
+
+ public bool IsCode(params int[] ids)
+ {
+ return ids.Contains(Id) || Alias != 0 && ids.Contains(Alias);
+ }
+
+ public bool IsOriginalCode(int id)
+ {
+ return Id == id || Alias - Id < 10 && Alias == id;
+ }
+
+ public bool HasXyzMaterial()
+ {
+ return Overlays.Count > 0;
+ }
+
+ public bool HasXyzMaterial(int count)
+ {
+ return Overlays.Count >= count;
+ }
+
+ public bool HasXyzMaterial(int count, int cardid)
+ {
+ return Overlays.Count >= count && Overlays.Contains(cardid);
+ }
+
+ public int GetDefensePower()
+ {
+ return IsAttack() ? Attack : Defense;
+ }
+
+ public bool Equals(ClientCard card)
+ {
+ return ReferenceEquals(this, card);
+ }
+ }
}
\ No newline at end of file
diff --git a/Game/ClientField.cs b/ExecutorBase/Game/ClientField.cs
similarity index 96%
rename from Game/ClientField.cs
rename to ExecutorBase/Game/ClientField.cs
index 6b4eff5e..82baeda7 100644
--- a/Game/ClientField.cs
+++ b/ExecutorBase/Game/ClientField.cs
@@ -1,352 +1,352 @@
-using System.Collections.Generic;
-using System.Linq;
-using WindBot.Game.AI;
-using YGOSharp.OCGWrapper.Enums;
-
-namespace WindBot.Game
-{
- public class ClientField
- {
- public IList Hand { get; private set; }
- public ClientCard[] MonsterZone { get; private set; }
- public ClientCard[] SpellZone { get; private set; }
- public IList Graveyard { get; private set; }
- public IList Banished { get; private set; }
- public IList Deck { get; private set; }
- public IList ExtraDeck { get; private set; }
-
- public int LifePoints;
- public ClientCard BattlingMonster;
- public bool UnderAttack;
-
- public ClientField()
- {
- }
-
- public void Init(int deck, int extra)
- {
- Hand = new List();
- MonsterZone = new ClientCard[7];
- SpellZone = new ClientCard[8];
- Graveyard = new List();
- Banished = new List();
- Deck = new List();
- ExtraDeck = new List();
-
- for (int i = 0; i < deck; ++i)
- Deck.Add(new ClientCard(0, CardLocation.Deck, -1));
- for (int i = 0; i < extra; ++i)
- ExtraDeck.Add(new ClientCard(0, CardLocation.Extra, -1));
- }
-
- public int GetMonstersExtraZoneCount()
- {
- int count = 0;
- if (MonsterZone[5] != null)
- count++;
- if (MonsterZone[6] != null)
- count++;
- return count;
- }
- public int GetMonsterCount()
- {
- return GetCount(MonsterZone);
- }
-
- public int GetSpellCount()
- {
- return GetCount(SpellZone);
- }
-
- public int GetHandCount()
- {
- return GetCount(Hand);
- }
-
- public int GetSpellCountWithoutField()
- {
- int count = 0;
- for (int i = 0; i < 5; ++i)
- {
- if (SpellZone[i] != null)
- ++count;
- }
- return count;
- }
-
- ///
- /// Count Column
- ///
- /// range of zone 0-4
- public int GetColumnCount(int zone, bool IncludeExtraMonsterZone = true)
- {
- int count = 0;
- if (SpellZone[zone] != null)
- count++;
- if (MonsterZone[zone] != null)
- count++;
- if(zone == 1 && IncludeExtraMonsterZone)
- {
- if (MonsterZone[5] != null)
- count++;
- }
- if (zone == 3 && IncludeExtraMonsterZone)
- {
- if (MonsterZone[6] != null)
- count++;
- }
- return count;
- }
-
- public int GetFieldCount()
- {
- return GetSpellCount() + GetMonsterCount();
- }
-
- public int GetFieldHandCount()
- {
- return GetSpellCount() + GetMonsterCount() + GetHandCount();
- }
-
- public bool IsFieldEmpty()
- {
- return GetMonsters().Count == 0 && GetSpells().Count == 0;
- }
-
- public int GetLinkedZones()
- {
- int zones = 0;
- for (int i = 0; i < 7; i++)
- {
- zones |= MonsterZone[i]?.GetLinkedZones() ?? 0;
- }
- return zones;
- }
-
- public List GetMonsters()
- {
- return GetCards(MonsterZone);
- }
-
- public List GetGraveyardMonsters()
- {
- return GetCards(Graveyard, CardType.Monster);
- }
-
- public List GetGraveyardSpells()
- {
- return GetCards(Graveyard, CardType.Spell);
- }
-
- public List GetGraveyardTraps()
- {
- return GetCards(Graveyard, CardType.Trap);
- }
-
- public List