Commit 078ad579 authored by Tang Xinwei's avatar Tang Xinwei

Revert "发牌姬第二期AI智力修复:盖谜题、时间魔术师、链接召唤过滤、宝箱怪逻辑"

This reverts commit 7e8bc837.
parent 7e8bc837
Pipeline #29863 passed with stages
in 1 minute and 50 seconds
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using YGOSharp.OCGWrapper.Enums; using YGOSharp.OCGWrapper.Enums;
...@@ -229,75 +229,8 @@ namespace WindBot.Game.AI ...@@ -229,75 +229,8 @@ namespace WindBot.Game.AI
AddExecutor(ExecutorType.Activate, _CardId.VaylantzWorld_KonigWissen, DefaultVaylantzWorld_KonigWissen); AddExecutor(ExecutorType.Activate, _CardId.VaylantzWorld_KonigWissen, DefaultVaylantzWorld_KonigWissen);
AddExecutor(ExecutorType.Activate, _CardId.SantaClaws); AddExecutor(ExecutorType.Activate, _CardId.SantaClaws);
AddExecutor(ExecutorType.SpellSet, DefaultSetForDiabellze); AddExecutor(ExecutorType.SpellSet, DefaultSetForDiabellze);
DealerMaidenModeAddCardExecutor();//发牌姬行为放到单独函数统一管理
}
void DealerMaidenModeAddCardExecutor()
{
SetFuncFilter(ExecutorType.Repos, () => {
if (Card.IsCode(1102515)) return false;
return true;
});
SetFuncFilter(ExecutorType.Activate, () => {
if (Card.IsCode(5990062)) return Bot.HasInSpellZone(9373534); //[大逆转谜题]只有在自己场上有手里剑覆盖的场合才发动
if (Card.IsCode(3493058)) return Enemy.GetSpellCount() > 0; //[骰子旋风]对方玩家场上有魔陷才发动
if (Card.IsCode(22802010)) //[无差别崩坏]自己场上怪兽少于对方才发动
return Bot.MonsterZone.Count(c => c != null && c.IsFaceup() && !c.HasType(CardType.Link)) < Enemy.MonsterZone.Count(c => c != null && c.IsFaceup() && !c.HasType(CardType.Link));
return false;
});
SetFuncFilter(ExecutorType.SummonOrSet, () => {
if (Card.IsCode(71625222)) return Enemy.GetMonsterCount() > 0; //[时间魔术师]对方场上有怪兽存在才召唤
int[] codes = new[] {23434538, 46502744, 87170768, 25137581,14558127,60643553,27204311,
94145021,59438930,2830693,19665973,18964575,34267821,24508238,78661338,84192580,
52038441,62015408
};
if (Card.IsCode(codes)) return false;//过滤手坑
return true;
});
SetFuncFilter(ExecutorType.SpSummon,() => {
if (Card.HasType(CardType.Link)) //链接怪兽特殊召唤前过滤
{
List<ClientCard> cards = Bot.GetMonsters();
List<ClientCard> noLinkCards = Bot.GetMonsters().Where(card =>
card == null || card.IsFacedown() || card.Level >= 8 || card.LinkCount >= 4 ||
card.Rank >= 8 || card.Attack >= 3000).ToList();
foreach (var card in noLinkCards) cards.Remove(card);
int link_count = 0;
foreach (var card in cards)
{
link_count += (card.HasType(CardType.Link)) ? card.LinkCount : 1;
if (link_count >= Card.LinkCount) return true;
}
}
return false;
});
AddExecutor(ExecutorType.Activate, DefaultGambleCard);//默认发动的赌博卡
AddExecutor(ExecutorType.SpellSet, 9373534);//[封魔手里剑]始终盖放
}
BattlePhaseAction DealerMaidenModeOnSelectAttackTarget(ClientCard attacker, IList<ClientCard> defenders)
{
if (attacker.IsCode(1102515)) //暗黑之宝箱怪 LV3
{
List<ClientCard> attakposCards = defenders.Where(card => card != null && card.IsAttack()).ToList();
attakposCards.Sort(CardContainer.CompareCardAttack);
if (attakposCards.Count() <= 0) return null;
foreach (ClientCard defender in attakposCards)
{
attacker.RealPower = attacker.Attack;
defender.RealPower = defender.Attack;
if (!OnPreBattleBetween(attacker, defender)) continue;
if ((defender.RealPower - attacker.RealPower > Bot.LifePoints) || attacker.RealPower > defender.RealPower) continue;
return AI.Attack(attacker, defender);
}
}
return null;
} }
protected int lightningStormOption = -1; protected int lightningStormOption = -1;
Dictionary<int, int> calledbytheGraveIdCountMap = new Dictionary<int, int>(); Dictionary<int, int> calledbytheGraveIdCountMap = new Dictionary<int, int>();
List<int> crossoutDesignatorIdList = new List<int>(); List<int> crossoutDesignatorIdList = new List<int>();
...@@ -382,13 +315,11 @@ namespace WindBot.Game.AI ...@@ -382,13 +315,11 @@ namespace WindBot.Game.AI
/// <returns>BattlePhaseAction including the target, or null (in this situation, GameAI will check the next attacker)</returns> /// <returns>BattlePhaseAction including the target, or null (in this situation, GameAI will check the next attacker)</returns>
public override BattlePhaseAction OnSelectAttackTarget(ClientCard attacker, IList<ClientCard> defenders) public override BattlePhaseAction OnSelectAttackTarget(ClientCard attacker, IList<ClientCard> defenders)
{ {
var action = DealerMaidenModeOnSelectAttackTarget(attacker, defenders); foreach (ClientCard defender in defenders)
if(action != null) return action;
foreach (ClientCard defender in defenders)
{ {
attacker.RealPower = attacker.Attack; attacker.RealPower = attacker.Attack;
defender.RealPower = defender.GetDefensePower(); defender.RealPower = defender.GetDefensePower();
if (!OnPreBattleBetween(attacker, defender))//对这个逻辑进行修改 if (!OnPreBattleBetween(attacker, defender))
continue; continue;
if (attacker.RealPower > defender.RealPower || (attacker.RealPower >= defender.RealPower && attacker.IsLastAttacker && defender.IsAttack())) if (attacker.RealPower > defender.RealPower || (attacker.RealPower >= defender.RealPower && attacker.IsLastAttacker && defender.IsAttack()))
...@@ -581,10 +512,10 @@ namespace WindBot.Game.AI ...@@ -581,10 +512,10 @@ namespace WindBot.Game.AI
return false; return false;
} }
/// <summary> /// <summary>
/// Set when this card can't beat the enemies /// Set when this card can't beat the enemies
/// </summary> /// </summary>
public override bool OnSelectMonsterSummonOrSet(ClientCard card) public override bool OnSelectMonsterSummonOrSet(ClientCard card)
{ {
return card.Level <= 4 && Bot.GetMonsters().Count(m => m.IsFaceup()) == 0 && Util.IsAllEnemyBetterThanValue(card.Attack, true); return card.Level <= 4 && Bot.GetMonsters().Count(m => m.IsFaceup()) == 0 && Util.IsAllEnemyBetterThanValue(card.Attack, true);
} }
...@@ -616,740 +547,672 @@ namespace WindBot.Game.AI ...@@ -616,740 +547,672 @@ namespace WindBot.Game.AI
extraDeck[shuffleCount] = extraDeck[index]; extraDeck[shuffleCount] = extraDeck[index];
extraDeck[index] = tempCard; extraDeck[index] = tempCard;
} }
return Util.CheckSelectCount(extraDeck, cards, min, max); return Util.CheckSelectCount(extraDeck, cards, min, max);
} }
if (hint == HintMsg.LinkMaterial)
return null;
}
public override void OnReceivingAnnouce(int player, int data)
{
if (player == 1 && data == Util.GetStringId(_CardId.LightningStorm, 0) || data == Util.GetStringId(_CardId.LightningStorm, 1))
{
lightningStormOption = data - Util.GetStringId(_CardId.LightningStorm, 0);
}
base.OnReceivingAnnouce(player, data);
}
public override void OnChainEnd()
{
lightningStormOption = -1;
base.OnChainEnd();
}
/// <summary>
/// Reset variables for new turn.
/// </summary>
public override void OnNewTurn()
{
if (Duel.Turn <= 1) calledbytheGraveIdCountMap.Clear();
List<int> keyList = calledbytheGraveIdCountMap.Keys.ToList();
foreach (int dic in keyList)
{ {
if (AI.HaveSelectedCards()) return null; if (calledbytheGraveIdCountMap[dic] > 0)
List<ClientCard> result = new List<ClientCard>(cards);
List<ClientCard> powerfulMonsters = new List<ClientCard>();
List<ClientCard> lowMonsters = new List<ClientCard>();
foreach (ClientCard card in result)
{ {
if (card.Level >= 8 || card.LinkCount >= 4 || calledbytheGraveIdCountMap[dic] -= 1;
card.Rank >= 8 || card.Attack >= 3000) powerfulMonsters.Add(card); }
else lowMonsters.Add(card); }
} crossoutDesignatorIdList.Clear();
lowMonsters.Sort(CardContainer.CompareCardAttack);
powerfulMonsters.Sort(CardContainer.CompareCardAttack); base.OnNewTurn();
powerfulMonsters.Reverse(); }
lowMonsters.AddRange(powerfulMonsters);
return Util.CheckSelectCount(lowMonsters, cards, min, max); public override void OnMove(ClientCard card, int previousControler, int previousLocation, int currentControler, int currentLocation)
} {
if (hint == HintMsg.Destroy) if (card != null)
{ {
if (AI.HaveSelectedCards()) return null; ClientCard currentSolvingChain = Duel.GetCurrentSolvingChainCard();
//[骰子旋风]破坏对方场上的魔法陷阱 if (currentSolvingChain != null && currentLocation == (int)CardLocation.Removed)
List<ClientCard> ccards = new List<ClientCard>(cards);
bool spellCard = true;
List<ClientCard> enemyCards = new List<ClientCard>();
List<ClientCard> botCards = new List<ClientCard>();
foreach (ClientCard card in ccards)
{ {
if (card == null) continue; int originId = card.Id;
if (!card.HasType(CardType.Spell) && !card.HasType(CardType.Trap)) if (card.Data != null)
{ {
spellCard = false; if (card.Data.Alias > 0) originId = card.Data.Alias;
break; else originId = card.Id;
}
if (currentSolvingChain.IsCode(_CardId.CalledByTheGrave))
{
calledbytheGraveIdCountMap[originId] = 2;
}
if (currentSolvingChain.IsCode(_CardId.CrossoutDesignator))
{
crossoutDesignatorIdList.Add(originId);
}
}
}
base.OnMove(card, previousControler, previousLocation, currentControler, currentLocation);
}
/// <summary>
/// Destroy face-down cards first, in our turn.
/// </summary>
protected bool DefaultMysticalSpaceTyphoon()
{
if (Duel.CurrentChain.Any(card => card.IsCode(_CardId.MysticalSpaceTyphoon)))
{
return false;
}
List<ClientCard> 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;
}
/// <summary>
/// Destroy face-down cards first, in our turn.
/// </summary>
protected bool DefaultCosmicCyclone()
{
foreach (ClientCard card in Duel.CurrentChain)
if (card.IsCode(_CardId.CosmicCyclone))
return false;
return (Bot.LifePoints > 1000) && DefaultMysticalSpaceTyphoon();
}
/// <summary>
/// Activate if avail.
/// </summary>
protected bool DefaultGalaxyCyclone()
{
List<ClientCard> 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;
}
/// <summary>
/// Set the highest ATK level 4+ effect enemy monster.
/// </summary>
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;
}
/// <summary>
/// Return problematic monster, and if this card become target, return any enemy monster.
/// </summary>
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;
}
/// <summary>
/// Revive the best monster when we don't have better one in field.
/// </summary>
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;
}
/// <summary>
/// Default Scapegoat effect
/// </summary>
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;
}
/// <summary>
/// Always active in opponent's turn.
/// </summary>
protected bool DefaultMaxxC()
{
if (DefaultCheckWhetherCardIsNegated(Card)) return false;
return Duel.Player == 1;
}
/// <summary>
/// Always disable opponent's effect except some cards like UpstartGoblin
/// </summary>
protected bool DefaultAshBlossomAndJoyousSpring()
{
if (DefaultCheckWhetherCardIsNegated(Card)) return false;
int[] ignoreList = {
_CardId.MacroCosmos,
_CardId.UpstartGoblin,
_CardId.CyberEmergency,
_CardId.TheAgentOfCreationVenus
};
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;
}
/// <summary>
/// Always activate unless the activating card is disabled
/// </summary>
protected bool DefaultGhostOgreAndSnowRabbit()
{
if (DefaultCheckWhetherCardIsNegated(Card)) return false;
if (Util.GetLastChainCard() != null && Util.GetLastChainCard().IsDisabled())
return false;
return DefaultTrap();
}
/// <summary>
/// Always disable opponent's effect
/// </summary>
protected bool DefaultGhostBelleAndHauntedMansion()
{
if (DefaultCheckWhetherCardIsNegated(Card)) return false;
return DefaultTrap();
}
/// <summary>
/// Same as DefaultBreakthroughSkill
/// </summary>
protected bool DefaultEffectVeiler()
{
if (DefaultCheckWhetherCardIsNegated(Card)) return false;
ClientCard LastChainCard = Util.GetLastChainCard();
if (LastChainCard != null && (LastChainCard.IsCode(_CardId.GalaxySoldier) && Enemy.Hand.Count >= 3
|| LastChainCard.IsCode(_CardId.EffectVeiler, _CardId.InfiniteImpermanence)))
return false;
return DefaultBreakthroughSkill();
}
/// <summary>
/// Chain common hand traps
/// </summary>
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();
} }
if (card.Controller == 1) enemyCards.Add(card); }
else botCards.Add(card); }
} return false;
if (spellCard) }
/// <summary>
/// Default InfiniteImpermanence effect
/// </summary>
protected bool DefaultInfiniteImpermanence()
{
if (DefaultCheckWhetherCardIsNegated(Card)) return false;
// TODO: disable s & t
ClientCard LastChainCard = Util.GetLastChainCard();
if (LastChainCard != null && (LastChainCard.IsCode(_CardId.GalaxySoldier) && Enemy.Hand.Count >= 3
|| LastChainCard.IsCode(_CardId.EffectVeiler, _CardId.InfiniteImpermanence)))
return false;
return DefaultDisableMonster();
}
/// <summary>
/// Chain the enemy monster, or disable monster like Rescue Rabbit.
/// </summary>
protected bool DefaultBreakthroughSkill()
{
if (!DefaultUniqueTrap())
return false;
return DefaultDisableMonster();
}
/// <summary>
/// Chain the enemy monster, or disable monster like Rescue Rabbit.
/// </summary>
protected bool DefaultDisableMonster()
{
if (Duel.Player == 1)
{
ClientCard target = Enemy.MonsterZone.GetShouldBeDisabledBeforeItUseEffectMonster();
if (target != null)
{ {
enemyCards.AddRange(botCards); AI.SelectCard(target);
return Util.CheckSelectCount(enemyCards, cards, min, max); return true;
} }
} }
return null;
} ClientCard LastChainCard = Util.GetLastChainCard();
public override void OnReceivingAnnouce(int player, int data) if (LastChainCard != null && LastChainCard.Controller == 1 && LastChainCard.Location == CardLocation.MonsterZone &&
{ !LastChainCard.IsDisabled() && !LastChainCard.IsShouldNotBeTarget() && !LastChainCard.IsShouldNotBeSpellTrapTarget())
if (player == 1 && data == Util.GetStringId(_CardId.LightningStorm, 0) || data == Util.GetStringId(_CardId.LightningStorm, 1)) {
{ AI.SelectCard(LastChainCard);
lightningStormOption = data - Util.GetStringId(_CardId.LightningStorm, 0); return true;
} }
base.OnReceivingAnnouce(player, data); if (Bot.BattlingMonster != null && Enemy.BattlingMonster != null)
} {
if (!Enemy.BattlingMonster.IsDisabled() && Enemy.BattlingMonster.IsCode(_CardId.EaterOfMillions))
public override void OnChainEnd() {
{ AI.SelectCard(Enemy.BattlingMonster);
lightningStormOption = -1; return true;
base.OnChainEnd(); }
} }
/// <summary> if (Duel.Phase == DuelPhase.BattleStart && Duel.Player == 1 &&
/// Reset variables for new turn. Enemy.HasInMonstersZone(_CardId.NumberS39UtopiaTheLightning, true))
/// </summary> {
public override void OnNewTurn() AI.SelectCard(_CardId.NumberS39UtopiaTheLightning);
{ return true;
if (Duel.Turn <= 1) calledbytheGraveIdCountMap.Clear(); }
List<int> keyList = calledbytheGraveIdCountMap.Keys.ToList();
foreach (int dic in keyList) return false;
{ }
if (calledbytheGraveIdCountMap[dic] > 0)
{ /// <summary>
calledbytheGraveIdCountMap[dic] -= 1; /// Activate only except this card is the target or we summon monsters.
} /// </summary>
} protected bool DefaultSolemnJudgment()
crossoutDesignatorIdList.Clear(); {
return !Util.IsChainTargetOnly(Card) && !(Duel.Player == 0 && Duel.LastChainPlayer == -1) && !DefaultOnlyHorusSpSummoning() && DefaultTrap();
base.OnNewTurn(); }
}
/// <summary>
public override void OnMove(ClientCard card, int previousControler, int previousLocation, int currentControler, int currentLocation) /// Activate only except we summon monsters.
{ /// </summary>
if (card != null) protected bool DefaultSolemnWarning()
{ {
ClientCard currentSolvingChain = Duel.GetCurrentSolvingChainCard(); return (Bot.LifePoints > 2000) && !(Duel.Player == 0 && Duel.LastChainPlayer == -1) && !DefaultOnlyHorusSpSummoning() && DefaultTrap();
if (currentSolvingChain != null && currentLocation == (int)CardLocation.Removed) }
{
int originId = card.Id; /// <summary>
if (card.Data != null) /// Activate only except we summon monsters.
{ /// </summary>
if (card.Data.Alias > 0) originId = card.Data.Alias; protected bool DefaultSolemnStrike()
else originId = card.Id; {
} return (Bot.LifePoints > 1500) && !(Duel.Player == 0 && Duel.LastChainPlayer == -1) && !DefaultOnlyHorusSpSummoning() && DefaultTrap();
if (currentSolvingChain.IsCode(_CardId.CalledByTheGrave)) }
{
calledbytheGraveIdCountMap[originId] = 2; /// <summary>
} /// Check whether only Horus monster is special summoning.
if (currentSolvingChain.IsCode(_CardId.CrossoutDesignator)) /// If returning true, should not negate the special summon since it can be special summoned again.
{ /// </summary>
crossoutDesignatorIdList.Add(originId); /// <returns></returns>
} protected bool DefaultOnlyHorusSpSummoning()
} {
} if (Duel.SummoningCards.Count != 0)
base.OnMove(card, previousControler, previousLocation, currentControler, currentLocation); {
} bool notOnlyHorusFlag = false;
foreach (ClientCard card in Duel.SummoningCards)
/// <summary> {
/// Destroy face-down cards first, in our turn. if (!card.HasSetcode(_Setcode.Horus) || card.LastLocation != CardLocation.Grave)
/// </summary> {
protected bool DefaultMysticalSpaceTyphoon() notOnlyHorusFlag = true;
{ break;
if (Duel.CurrentChain.Any(card => card.IsCode(_CardId.MysticalSpaceTyphoon))) }
{ }
return false; return !notOnlyHorusFlag;
} }
return false;
List<ClientCard> spells = Enemy.GetSpells(); }
if (spells.Count == 0)
return false; /// <summary>
/// Activate when all enemy monsters have better ATK.
ClientCard selected = Enemy.SpellZone.GetFloodgate(); /// </summary>
protected bool DefaultTorrentialTribute()
if (selected == null) {
{ return !Util.HasChainedTrap(0) && Util.IsAllEnemyBetter(true);
if (Duel.Player == 0) }
selected = spells.FirstOrDefault(card => card.IsFacedown());
if (Duel.Player == 1) /// <summary>
selected = spells.FirstOrDefault(card => card.HasType(CardType.Continuous) || card.HasType(CardType.Equip) || card.HasType(CardType.Field)); /// Activate enemy have more S&T.
} /// </summary>
protected bool DefaultHeavyStorm()
if (selected == null) {
return false; return Bot.GetSpellCount() < Enemy.GetSpellCount();
AI.SelectCard(selected); }
return true;
} /// <summary>
/// Activate before other winds, if enemy have more than 2 S&T.
/// <summary> /// </summary>
/// Destroy face-down cards first, in our turn. protected bool DefaultHarpiesFeatherDusterFirst()
/// </summary> {
protected bool DefaultCosmicCyclone() return Enemy.GetSpellCount() >= 2;
{ }
foreach (ClientCard card in Duel.CurrentChain)
if (card.IsCode(_CardId.CosmicCyclone)) /// <summary>
return false; /// Activate when one enemy monsters have better ATK.
return (Bot.LifePoints > 1000) && DefaultMysticalSpaceTyphoon(); /// </summary>
} protected bool DefaultHammerShot()
{
/// <summary> return Util.IsOneEnemyBetter(true);
/// Activate if avail. }
/// </summary>
protected bool DefaultGalaxyCyclone() /// <summary>
{ /// Activate when one enemy monsters have better ATK or DEF.
List<ClientCard> spells = Enemy.GetSpells(); /// </summary>
if (spells.Count == 0) protected bool DefaultDarkHole()
return false; {
return Util.IsOneEnemyBetter();
ClientCard selected = null; }
if (Card.Location == CardLocation.Grave) /// <summary>
{ /// Activate when one enemy monsters have better ATK or DEF.
selected = Util.GetBestEnemySpell(true); /// </summary>
} protected bool DefaultRaigeki()
else {
{ return Util.IsOneEnemyBetter();
selected = spells.FirstOrDefault(card => card.IsFacedown()); }
}
/// <summary>
if (selected == null) /// Activate when one enemy monsters have better ATK or DEF.
return false; /// </summary>
protected bool DefaultSmashingGround()
AI.SelectCard(selected); {
return true; return Util.IsOneEnemyBetter();
} }
/// <summary> /// <summary>
/// Set the highest ATK level 4+ effect enemy monster. /// Activate when we have more than 15 cards in deck.
/// </summary> /// </summary>
protected bool DefaultBookOfMoon() protected bool DefaultPotOfDesires()
{ {
if (Util.IsAllEnemyBetter(true)) return Bot.Deck.Count > 15;
{ }
ClientCard monster = Enemy.GetMonsters().GetHighestAttackMonster(true);
if (monster != null && monster.HasType(CardType.Effect) && !monster.HasType(CardType.Link) && (monster.HasType(CardType.Xyz) || monster.Level > 4)) /// <summary>
{ /// Set traps only and avoid block the activation of other cards.
AI.SelectCard(monster); /// </summary>
return true; protected bool DefaultSpellSet()
} {
} return (Card.IsTrap() || Card.HasType(CardType.QuickPlay) || DefaultSpellMustSetFirst()) && Bot.GetSpellCountWithoutField() < 4;
return false; }
}
/// <summary>
/// <summary> /// Summon with no tribute, or with tributes ATK lower.
/// Return problematic monster, and if this card become target, return any enemy monster. /// </summary>
/// </summary> protected bool DefaultMonsterSummon()
protected bool DefaultCompulsoryEvacuationDevice() {
{ if (Card.Level <= 4)
ClientCard target = Util.GetProblematicEnemyMonster(0, true); return true;
if (target != null)
{ if (!UniqueFaceupMonster())
AI.SelectCard(target); return false;
return true; int tributecount = (int)Math.Ceiling((Card.Level - 4.0d) / 2.0d);
} for (int j = 0; j < 7; ++j)
if (Util.IsChainTarget(Card)) {
{ ClientCard tributeCard = Bot.MonsterZone[j];
ClientCard monster = Util.GetBestEnemyMonster(false, true); if (tributeCard == null) continue;
if (monster != null) if (tributeCard.GetDefensePower() < Card.Attack)
{ tributecount--;
AI.SelectCard(monster); }
return true; return tributecount <= 0;
} }
}
return false; /// <summary>
} /// Activate when we have no field.
/// </summary>
/// <summary> protected bool DefaultField()
/// Revive the best monster when we don't have better one in field. {
/// </summary> return Bot.SpellZone[5] == null;
protected bool DefaultCallOfTheHaunted() }
{
if (!Util.IsAllEnemyBetter(true)) /// <summary>
return false; /// Turn if all enemy is better.
ClientCard selected = Bot.Graveyard.GetMatchingCards(card => card.IsCanRevive()).OrderByDescending(card => card.Attack).FirstOrDefault(); /// </summary>
AI.SelectCard(selected); protected bool DefaultMonsterRepos()
return true; {
} if (Card.IsMonsterInvincible())
return Card.IsDefense();
/// <summary>
/// Default Scapegoat effect if (Card.Attack == 0)
/// </summary> {
protected bool DefaultScapegoat() if (Card.IsFaceup() && Card.IsAttack())
{ return true;
if (DefaultSpellWillBeNegated()) return false; if (Card.IsFaceup() && Card.IsDefense())
if (Duel.Player == 0) return false; 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(_CardId.BlueEyesChaosMAXDragon, true) &&
{ Card.IsAttack() && (4000 - Card.Defense) * 2 > (4000 - Card.Attack))
if (Enemy.HasInMonstersZone(new[] return false;
{ if (Enemy.HasInMonstersZone(_CardId.BlueEyesChaosMAXDragon, true) &&
_CardId.UltimateConductorTytanno, Card.IsDefense() && Card.IsFaceup() &&
_CardId.InvokedPurgatrio, (4000 - Card.Defense) * 2 > (4000 - Card.Attack))
_CardId.ChaosAncientGearGiant, return true;
_CardId.UltimateAncientGearGolem,
_CardId.RedDragonArchfiend bool enemyBetter = Util.IsAllEnemyBetter();
}, true)) return false; if (Card.IsAttack() && enemyBetter)
if (Util.GetTotalAttackingMonsterAttack(1) >= Bot.LifePoints) return true; return true;
} if (Card.IsDefense() && !enemyBetter && (Card.Attack >= Card.Defense || Card.Attack >= Util.GetBestPower(Enemy)))
return false; return true;
}
/// <summary> return false;
/// Always active in opponent's turn. }
/// </summary>
protected bool DefaultMaxxC() /// <summary>
{ /// If spell will be negated
if (DefaultCheckWhetherCardIsNegated(Card)) return false; /// </summary>
return Duel.Player == 1; protected bool DefaultSpellWillBeNegated()
} {
/// <summary> return (Bot.HasInSpellZone(_CardId.ImperialOrder, true, true) || Enemy.HasInSpellZone(_CardId.ImperialOrder, true)) && !Util.ChainContainsCard(_CardId.ImperialOrder)
/// Always disable opponent's effect except some cards like UpstartGoblin || DefaultCheckWhetherCardIsNegated(Card);
/// </summary> }
protected bool DefaultAshBlossomAndJoyousSpring()
{ /// <summary>
if (DefaultCheckWhetherCardIsNegated(Card)) return false; /// If trap will be negated
int[] ignoreList = { /// </summary>
_CardId.MacroCosmos, protected bool DefaultTrapWillBeNegated()
_CardId.UpstartGoblin, {
_CardId.CyberEmergency, return (Bot.HasInSpellZone(_CardId.RoyalDecreel, true, true) || Enemy.HasInSpellZone(_CardId.RoyalDecreel, true)) && !Util.ChainContainsCard(_CardId.RoyalDecreel)
_CardId.TheAgentOfCreationVenus || DefaultCheckWhetherCardIsNegated(Card);
}; }
if (Util.GetLastChainCard().IsCode(ignoreList))
return false; /// <summary>
if (Util.GetLastChainCard().HasSetcode(0x11e) && Util.GetLastChainCard().Location == CardLocation.Hand) // Danger! archtype hand effect /// If spell must set first to activate
return false; /// </summary>
return Duel.LastChainPlayer == 1; protected bool DefaultSpellMustSetFirst()
} {
/// <summary> return Bot.HasInSpellZone(_CardId.AntiSpellFragrance, true, true) || Enemy.HasInSpellZone(_CardId.AntiSpellFragrance, true);
/// Always activate unless the activating card is disabled }
/// </summary>
protected bool DefaultGhostOgreAndSnowRabbit() /// <summary>
{ /// if spell/trap is the target or enermy activate HarpiesFeatherDuster
if (DefaultCheckWhetherCardIsNegated(Card)) return false; /// </summary>
if (Util.GetLastChainCard() != null && Util.GetLastChainCard().IsDisabled()) protected bool DefaultOnBecomeTarget()
return false; {
return DefaultTrap(); if (Util.IsChainTarget(Card)) return true;
} int[] destroyAllList =
/// <summary> {
/// Always disable opponent's effect _CardId.EvilswarmExcitonKnight,
/// </summary> _CardId.BlackRoseDragon,
protected bool DefaultGhostBelleAndHauntedMansion() _CardId.JudgmentDragon,
{ _CardId.TopologicTrisbaena,
if (DefaultCheckWhetherCardIsNegated(Card)) return false; _CardId.EvenlyMatched,
return DefaultTrap(); _CardId.DivineArsenalAAZEUS_SkyThunder
} };
/// <summary> int[] destroyAllMonsterList =
/// Same as DefaultBreakthroughSkill {
/// </summary> _CardId.DarkHole,
protected bool DefaultEffectVeiler() _CardId.InterruptedKaijuSlumber
{ };
if (DefaultCheckWhetherCardIsNegated(Card)) return false; int[] destroyAllOpponentMonsterList =
ClientCard LastChainCard = Util.GetLastChainCard(); {
if (LastChainCard != null && (LastChainCard.IsCode(_CardId.GalaxySoldier) && Enemy.Hand.Count >= 3 _CardId.Raigeki
|| LastChainCard.IsCode(_CardId.EffectVeiler, _CardId.InfiniteImpermanence))) };
return false; int[] destroyAllOpponentSpellList =
return DefaultBreakthroughSkill(); {
} _CardId.HarpiesFeatherDuster,
/// <summary> _CardId.DarkMagicAttack
/// Chain common hand traps };
/// </summary>
protected bool DefaultCalledByTheGrave() if (Util.ChainContainsCard(destroyAllList)) return true;
{ if (Enemy.HasInSpellZone(destroyAllOpponentSpellList, true) && Card.Location == CardLocation.SpellZone) return true;
int[] targetList = if (Util.ChainContainsCard(destroyAllMonsterList) && Card.Location == CardLocation.MonsterZone) return true;
{ if (Duel.CurrentChain.Any(c => c.Controller == 1 && c.IsCode(destroyAllOpponentMonsterList)) && Card.Location == CardLocation.MonsterZone) return true;
_CardId.MaxxC, if (lightningStormOption == 0 && Card.Location == CardLocation.MonsterZone && Card.IsAttack()) return true;
_CardId.LockBird, if (lightningStormOption == 1 && Card.Location == CardLocation.SpellZone) return true;
_CardId.GhostOgreAndSnowRabbit, // TODO: ChainContainsCard(id, player)
_CardId.AshBlossom, return false;
_CardId.GhostBelle, }
_CardId.EffectVeiler, /// <summary>
_CardId.ArtifactLancea /// Chain enemy activation or summon.
}; /// </summary>
if (Duel.LastChainPlayer == 1) protected bool DefaultTrap()
{ {
foreach (int id in targetList) if (DefaultCheckWhetherCardIsNegated(Card)) return false;
{ return (Duel.LastChainPlayer == -1 && Duel.LastSummonPlayer != 0) || Duel.LastChainPlayer == 1;
if (Util.GetLastChainCard().IsCode(id)) }
{
AI.SelectCard(id); /// <summary>
return UniqueFaceupSpell(); /// Activate when avail and no other our trap card in this chain or face-up.
} /// </summary>
} protected bool DefaultUniqueTrap()
} {
return false; if (Util.HasChainedTrap(0))
} return false;
/// <summary>
/// Default InfiniteImpermanence effect return UniqueFaceupSpell();
/// </summary> }
protected bool DefaultInfiniteImpermanence()
{ /// <summary>
if (DefaultCheckWhetherCardIsNegated(Card)) return false; /// Check no other our spell or trap card with same name face-up.
// TODO: disable s & t /// </summary>
ClientCard LastChainCard = Util.GetLastChainCard(); protected bool UniqueFaceupSpell()
if (LastChainCard != null && (LastChainCard.IsCode(_CardId.GalaxySoldier) && Enemy.Hand.Count >= 3 {
|| LastChainCard.IsCode(_CardId.EffectVeiler, _CardId.InfiniteImpermanence))) return !Bot.GetSpells().Any(card => card.IsCode(Card.Id) && card.IsFaceup());
return false; }
return DefaultDisableMonster();
} /// <summary>
/// <summary> /// Check no other our monster card with same name face-up.
/// Chain the enemy monster, or disable monster like Rescue Rabbit. /// </summary>
/// </summary> protected bool UniqueFaceupMonster()
protected bool DefaultBreakthroughSkill() {
{ return !Bot.GetMonsters().Any(card => card.IsCode(Card.Id) && card.IsFaceup());
if (!DefaultUniqueTrap()) }
return false;
return DefaultDisableMonster(); /// <summary>
} /// Dumb way to avoid the bot chain in mess.
/// <summary> /// </summary>
/// Chain the enemy monster, or disable monster like Rescue Rabbit. protected bool DefaultDontChainMyself()
/// </summary> {
protected bool DefaultDisableMonster() if (Type != ExecutorType.Activate)
{ return true;
if (Duel.Player == 1) if (Executors.Any(exec => exec.Type == Type && exec.CardId == Card.Id))
{ return false;
ClientCard target = Enemy.MonsterZone.GetShouldBeDisabledBeforeItUseEffectMonster(); return Duel.LastChainPlayer != 0;
if (target != null) }
{
AI.SelectCard(target); /// <summary>
return true; /// Draw when we have lower LP, or destroy it. Can be overrided.
} /// </summary>
} protected bool DefaultChickenGame()
{
ClientCard LastChainCard = Util.GetLastChainCard(); if (Executors.Count(exec => exec.Type == Type && exec.CardId == Card.Id) > 1)
return false;
if (LastChainCard != null && LastChainCard.Controller == 1 && LastChainCard.Location == CardLocation.MonsterZone && if (Card.IsFacedown())
!LastChainCard.IsDisabled() && !LastChainCard.IsShouldNotBeTarget() && !LastChainCard.IsShouldNotBeSpellTrapTarget()) return true;
{ if (Bot.LifePoints <= 1000)
AI.SelectCard(LastChainCard); return false;
return true; if (Bot.LifePoints <= Enemy.LifePoints && ActivateDescription == Util.GetStringId(_CardId.ChickenGame, 0))
}
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;
}
/// <summary>
/// Activate only except this card is the target or we summon monsters.
/// </summary>
protected bool DefaultSolemnJudgment()
{
return !Util.IsChainTargetOnly(Card) && !(Duel.Player == 0 && Duel.LastChainPlayer == -1) && !DefaultOnlyHorusSpSummoning() && DefaultTrap();
}
/// <summary>
/// Activate only except we summon monsters.
/// </summary>
protected bool DefaultSolemnWarning()
{
return (Bot.LifePoints > 2000) && !(Duel.Player == 0 && Duel.LastChainPlayer == -1) && !DefaultOnlyHorusSpSummoning() && DefaultTrap();
}
/// <summary>
/// Activate only except we summon monsters.
/// </summary>
protected bool DefaultSolemnStrike()
{
return (Bot.LifePoints > 1500) && !(Duel.Player == 0 && Duel.LastChainPlayer == -1) && !DefaultOnlyHorusSpSummoning() && DefaultTrap();
}
/// <summary>
/// Check whether only Horus monster is special summoning.
/// If returning true, should not negate the special summon since it can be special summoned again.
/// </summary>
/// <returns></returns>
protected bool DefaultOnlyHorusSpSummoning()
{
if (Duel.SummoningCards.Count != 0)
{
bool notOnlyHorusFlag = false;
foreach (ClientCard card in Duel.SummoningCards)
{
if (!card.HasSetcode(_Setcode.Horus) || card.LastLocation != CardLocation.Grave)
{
notOnlyHorusFlag = true;
break;
}
}
return !notOnlyHorusFlag;
}
return false;
}
/// <summary>
/// Activate when all enemy monsters have better ATK.
/// </summary>
protected bool DefaultTorrentialTribute()
{
return !Util.HasChainedTrap(0) && Util.IsAllEnemyBetter(true);
}
/// <summary>
/// Activate enemy have more S&T.
/// </summary>
protected bool DefaultHeavyStorm()
{
return Bot.GetSpellCount() < Enemy.GetSpellCount();
}
/// <summary>
/// Activate before other winds, if enemy have more than 2 S&T.
/// </summary>
protected bool DefaultHarpiesFeatherDusterFirst()
{
return Enemy.GetSpellCount() >= 2;
}
/// <summary>
/// Activate when one enemy monsters have better ATK.
/// </summary>
protected bool DefaultHammerShot()
{
return Util.IsOneEnemyBetter(true);
}
/// <summary>
/// Activate when one enemy monsters have better ATK or DEF.
/// </summary>
protected bool DefaultDarkHole()
{
return Util.IsOneEnemyBetter();
}
/// <summary>
/// Activate when one enemy monsters have better ATK or DEF.
/// </summary>
protected bool DefaultRaigeki()
{
return Util.IsOneEnemyBetter();
}
/// <summary>
/// Activate when one enemy monsters have better ATK or DEF.
/// </summary>
protected bool DefaultSmashingGround()
{
return Util.IsOneEnemyBetter();
}
/// <summary>
/// Activate when we have more than 15 cards in deck.
/// </summary>
protected bool DefaultPotOfDesires()
{
return Bot.Deck.Count > 15;
}
/// <summary>
/// Set traps only and avoid block the activation of other cards.
/// </summary>
protected bool DefaultSpellSet()
{
if (Card.Id == 15693423) return false;
if (Card.Id == 9373534) return true;
return (Card.IsTrap() || Card.HasType(CardType.QuickPlay) || DefaultSpellMustSetFirst()) && Bot.GetSpellCountWithoutField() < 4;
}
/// <summary>
/// Summon with no tribute, or with tributes ATK lower.
/// </summary>
protected bool DefaultMonsterSummon()
{
if (Card.Level <= 4)
return true;
if (!UniqueFaceupMonster())
return false;
if (DontSummon(Card))
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;
}
/// <summary>
/// Dont summon cards'id in the following list
/// </summary>
private bool DontSummon(ClientCard card)
{
if (card.HasSetcode(0x40) || card.HasSetcode(0xa4) || card.HasSetcode(0xd3)) return true;
int[] cardsname = new[] {74762582, 90179822, 16759958, 26964762, 42352091, 2511, 74018812, 76214441, 62886670, 69105797, 32391566, 94076521, 73625877, 1980574, 42090294, 68823957, 34976176, 89785779, 76133574, 3248469, 87102774
, 57647597, 37961969, 51993760, 87988305, 38339996, 37629703, 58131925, 71133680, 42790071, 34475451, 63009228, 24725825, 48427163, 86028783, 51852507, 29280589, 87462901, 73640163, 68120130, 84813516, 55461064, 59042331, 26775203, 89169343
, 67750322, 68819554, 26084285, 15613529, 19096726, 59546797, 12235475, 38695361, 37742478, 26914168, 43534808, 13313278, 99581584, 04192696, 89662736, 81109178, 18444902, 04807253, 12423762, 72318602, 86613346, 82489470, 16223761, 08152834/*像是手坑的时尚小垃圾*/
, 97268402/*效果遮蒙者*/, 24508238/*D.D.乌鸦*/, 94145021/*锁鸟*/
, 14558127, 14558128, 52038441, 52038442, 59438930, 59438931, 60643553, 60643554, 62015408, 62015409, 73642296, 73642297/*手坑六姐妹*/
, 15721123, 23434538, 25137581, 46502744, 80978111, 87170768, 94081496/*xx的G*/
, 17266660, 21074344, 94689635/*宣告者*/
, 18964575, 20450925, 19665973, 28427869, 27352108/*攻宣坑*/
};
if (card.IsCode(cardsname)) return true;
return false;
}
/// <summary>
/// Activate when we have no field.
/// </summary>
protected bool DefaultField()
{
return Bot.SpellZone[5] == null;
}
/// <summary>
/// Turn if all enemy is better.
/// </summary>
protected bool DefaultMonsterRepos()
{
if (Card.IsMonsterInvincible())
return Card.IsDefense();
if (Card.Attack == 0)
{
if (Card.IsFaceup() && Card.IsAttack())
return true;
if (Card.IsFaceup() && Card.IsDefense())
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();
if (Card.IsAttack() && enemyBetter)
return true;
if (Card.IsDefense() && !enemyBetter && (Card.Attack >= Card.Defense || Card.Attack >= Util.GetBestPower(Enemy)))
return true;
return false;
}
/// <summary>
/// If spell will be negated
/// </summary>
protected bool DefaultSpellWillBeNegated()
{
return (Bot.HasInSpellZone(_CardId.ImperialOrder, true, true) || Enemy.HasInSpellZone(_CardId.ImperialOrder, true)) && !Util.ChainContainsCard(_CardId.ImperialOrder)
|| DefaultCheckWhetherCardIsNegated(Card);
}
/// <summary>
/// If trap will be negated
/// </summary>
protected bool DefaultTrapWillBeNegated()
{
return (Bot.HasInSpellZone(_CardId.RoyalDecreel, true, true) || Enemy.HasInSpellZone(_CardId.RoyalDecreel, true)) && !Util.ChainContainsCard(_CardId.RoyalDecreel)
|| DefaultCheckWhetherCardIsNegated(Card);
}
/// <summary>
/// If spell must set first to activate
/// </summary>
protected bool DefaultSpellMustSetFirst()
{
return Bot.HasInSpellZone(_CardId.AntiSpellFragrance, true, true) || Enemy.HasInSpellZone(_CardId.AntiSpellFragrance, true);
}
/// <summary>
/// if spell/trap is the target or enermy activate HarpiesFeatherDuster
/// </summary>
protected bool DefaultOnBecomeTarget()
{
if (Util.IsChainTarget(Card)) return true;
int[] destroyAllList =
{
_CardId.EvilswarmExcitonKnight,
_CardId.BlackRoseDragon,
_CardId.JudgmentDragon,
_CardId.TopologicTrisbaena,
_CardId.EvenlyMatched,
_CardId.DivineArsenalAAZEUS_SkyThunder
};
int[] destroyAllMonsterList =
{
_CardId.DarkHole,
_CardId.InterruptedKaijuSlumber
};
int[] destroyAllOpponentMonsterList =
{
_CardId.Raigeki
};
int[] destroyAllOpponentSpellList =
{
_CardId.HarpiesFeatherDuster,
_CardId.DarkMagicAttack
};
if (Util.ChainContainsCard(destroyAllList)) return true;
if (Enemy.HasInSpellZone(destroyAllOpponentSpellList, true) && Card.Location == CardLocation.SpellZone) return true;
if (Util.ChainContainsCard(destroyAllMonsterList) && Card.Location == CardLocation.MonsterZone) return true;
if (Duel.CurrentChain.Any(c => c.Controller == 1 && c.IsCode(destroyAllOpponentMonsterList)) && Card.Location == CardLocation.MonsterZone) return true;
if (lightningStormOption == 0 && Card.Location == CardLocation.MonsterZone && Card.IsAttack()) return true;
if (lightningStormOption == 1 && Card.Location == CardLocation.SpellZone) return true;
// TODO: ChainContainsCard(id, player)
return false;
}
/// <summary>
/// Chain enemy activation or summon.
/// </summary>
protected bool DefaultTrap()
{
if (DefaultCheckWhetherCardIsNegated(Card)) return false;
return (Duel.LastChainPlayer == -1 && Duel.LastSummonPlayer != 0) || Duel.LastChainPlayer == 1;
}
/// <summary>
/// Activate when avail and no other our trap card in this chain or face-up.
/// </summary>
protected bool DefaultUniqueTrap()
{
if (Util.HasChainedTrap(0))
return false;
return UniqueFaceupSpell();
}
/// <summary>
/// Check no other our spell or trap card with same name face-up.
/// </summary>
protected bool UniqueFaceupSpell()
{
return !Bot.GetSpells().Any(card => card.IsCode(Card.Id) && card.IsFaceup());
}
/// <summary>
/// Check no other our monster card with same name face-up.
/// </summary>
protected bool UniqueFaceupMonster()
{
return !Bot.GetMonsters().Any(card => card.IsCode(Card.Id) && card.IsFaceup());
}
/// <summary>
/// Dumb way to avoid the bot chain in mess.
/// </summary>
protected bool DefaultDontChainMyself()
{
if (Type != ExecutorType.Activate)
return true;
if (Executors.Any(exec => exec.Type == Type && exec.CardId == Card.Id))
return false;
return Duel.LastChainPlayer != 0;
}
/// <summary>
/// Draw when we have lower LP, or destroy it. Can be overrided.
/// </summary>
protected bool DefaultChickenGame()
{
if (Executors.Count(exec => exec.Type == Type && exec.CardId == Card.Id) > 1)
return false;
if (Card.IsFacedown())
return true;
if (Bot.LifePoints <= 1000)
return false;
if (Bot.LifePoints <= Enemy.LifePoints && ActivateDescription == Util.GetStringId(_CardId.ChickenGame, 0))
return true; return true;
if (Bot.LifePoints > Enemy.LifePoints && ActivateDescription == Util.GetStringId(_CardId.ChickenGame, 1)) if (Bot.LifePoints > Enemy.LifePoints && ActivateDescription == Util.GetStringId(_CardId.ChickenGame, 1))
return true; return true;
...@@ -1760,14 +1623,5 @@ namespace WindBot.Game.AI ...@@ -1760,14 +1623,5 @@ namespace WindBot.Game.AI
} }
return false; return false;
} }
protected bool DefaultGambleCard()
{
int[] cardsname = new[] {3280747, 37812118, 50470982, 43061293, 37313786, 3493058, 38299233, 25173686, 71625222, 36562627, 19162134, 81172176, 21598948, 39537362, 36378044, 38143903, 96012004, 62784717, 84290642, 3549275, 41139112, 36708764, 74137509, 126218, 93078761, 76895648, 22802010, 83241722, 84397023, 31863912, 39454112, 59905358, 5990062, 9373534, 58577036
};
if (Card.IsCode(cardsname)) return true;
return false;
}
} }
} }
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using WindBot.Game.AI; using WindBot.Game.AI;
using YGOSharp.OCGWrapper.Enums; using YGOSharp.OCGWrapper.Enums;
using System;
using System.Threading;
namespace WindBot.Game namespace WindBot.Game
{ {
...@@ -50,6 +49,9 @@ namespace WindBot.Game ...@@ -50,6 +49,9 @@ namespace WindBot.Game
public void OnDeckError(string card) public void OnDeckError(string card)
{ {
_dialogs.SendDeckSorry(card); _dialogs.SendDeckSorry(card);
Thread.Sleep(1000);
_dialogs.SendSurrender();
Game.Connection.Close();
} }
/// <summary> /// <summary>
...@@ -235,10 +237,10 @@ namespace WindBot.Game ...@@ -235,10 +237,10 @@ namespace WindBot.Game
if (result != null) if (result != null)
return result; return result;
if (attackers.Count == 0) //如果自己场上没有可以攻击的怪兽直接返回 if (attackers.Count == 0)
return ToMainPhase2(); return ToMainPhase2();
if (defenders.Count == 0) //如果对方场上没有怪兽则直接攻击 if (defenders.Count == 0)
{ {
// Attack with the monster with the lowest attack first // Attack with the monster with the lowest attack first
ClientCard attacker = attackers[attackers.Count - 1]; ClientCard attacker = attackers[attackers.Count - 1];
...@@ -246,17 +248,17 @@ namespace WindBot.Game ...@@ -246,17 +248,17 @@ namespace WindBot.Game
} }
else else
{ {
for (int k = 0; k < attackers.Count; ++k) //如果对方场上有怪兽 for (int k = 0; k < attackers.Count; ++k)
{ {
ClientCard attacker = attackers[k]; ClientCard attacker = attackers[k];
attacker.IsLastAttacker = (k == attackers.Count - 1); attacker.IsLastAttacker = (k == attackers.Count - 1);
result = Executor.OnSelectAttackTarget(attacker, defenders);//这个函数决定是否要攻击 result = Executor.OnSelectAttackTarget(attacker, defenders);
if (result != null) if (result != null)
return result; return result;
} }
} }
if (!battle.CanMainPhaseTwo) //如果不能进战阶强制攻击 if (!battle.CanMainPhaseTwo)
return Attack(attackers[0], (defenders.Count == 0) ? null : defenders[0]); return Attack(attackers[0], (defenders.Count == 0) ? null : defenders[0]);
return ToMainPhase2(); return ToMainPhase2();
...@@ -754,7 +756,7 @@ namespace WindBot.Game ...@@ -754,7 +756,7 @@ namespace WindBot.Game
sorted.Sort(CardContainer.CompareCardAttack); sorted.Sort(CardContainer.CompareCardAttack);
IList<ClientCard> selected = new List<ClientCard>(); IList<ClientCard> selected = new List<ClientCard>();
for (int i = 0; i < min && i < sorted.Count; ++i) for (int i = 0; i < min && i < sorted.Count; ++i)
selected.Add(sorted[i]); selected.Add(sorted[i]);
...@@ -1172,15 +1174,10 @@ namespace WindBot.Game ...@@ -1172,15 +1174,10 @@ namespace WindBot.Game
if (!Executor.OnPreActivate(card)) if (!Executor.OnPreActivate(card))
return false; return false;
} }
Func<bool> Func = () => bool result = card != null && exec.Type == type &&
{ (exec.CardId == -1 || exec.CardId == card.Id) &&
if (Executor.FuncFilters.ContainsKey(exec.Type) && Executor.FuncFilters[exec.Type] != null (exec.Func == null || exec.Func());
&& !Executor.FuncFilters[exec.Type]()) return false; if (card.Id != 0 && type == ExecutorType.Activate && result)
return exec.Func == null || exec.Func();
};
bool result = card != null && exec.Type == type &&
(exec.CardId == -1 || exec.CardId == card.Id) && Func();
if (card.Id != 0 && type == ExecutorType.Activate && result)
{ {
int count = card.IsDisabled() ? 3 : 1; int count = card.IsDisabled() ? 3 : 1;
if (!_activatedCards.ContainsKey(card.Id)) if (!_activatedCards.ContainsKey(card.Id))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment