Commit 7e8bc837 authored by Tang Xinwei's avatar Tang Xinwei

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

+ 检测宝箱怪是否要攻击
parent 8b859976
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using YGOSharp.OCGWrapper.Enums;
......@@ -229,8 +229,75 @@ namespace WindBot.Game.AI
AddExecutor(ExecutorType.Activate, _CardId.VaylantzWorld_KonigWissen, DefaultVaylantzWorld_KonigWissen);
AddExecutor(ExecutorType.Activate, _CardId.SantaClaws);
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;
Dictionary<int, int> calledbytheGraveIdCountMap = new Dictionary<int, int>();
List<int> crossoutDesignatorIdList = new List<int>();
......@@ -315,11 +382,13 @@ namespace WindBot.Game.AI
/// <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)
{
foreach (ClientCard defender in defenders)
var action = DealerMaidenModeOnSelectAttackTarget(attacker, defenders);
if(action != null) return action;
foreach (ClientCard defender in defenders)
{
attacker.RealPower = attacker.Attack;
defender.RealPower = defender.GetDefensePower();
if (!OnPreBattleBetween(attacker, defender))
if (!OnPreBattleBetween(attacker, defender))//对这个逻辑进行修改
continue;
if (attacker.RealPower > defender.RealPower || (attacker.RealPower >= defender.RealPower && attacker.IsLastAttacker && defender.IsAttack()))
......@@ -512,10 +581,10 @@ namespace WindBot.Game.AI
return false;
}
/// <summary>
/// Set when this card can't beat the enemies
/// </summary>
public override bool OnSelectMonsterSummonOrSet(ClientCard card)
/// <summary>
/// Set when this card can't beat the enemies
/// </summary>
public override bool OnSelectMonsterSummonOrSet(ClientCard card)
{
return card.Level <= 4 && Bot.GetMonsters().Count(m => m.IsFaceup()) == 0 && Util.IsAllEnemyBetterThanValue(card.Attack, true);
}
......@@ -547,672 +616,740 @@ namespace WindBot.Game.AI
extraDeck[shuffleCount] = extraDeck[index];
extraDeck[index] = tempCard;
}
return Util.CheckSelectCount(extraDeck, cards, min, max);
}
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 (calledbytheGraveIdCountMap[dic] > 0)
{
calledbytheGraveIdCountMap[dic] -= 1;
}
}
crossoutDesignatorIdList.Clear();
base.OnNewTurn();
}
public override void OnMove(ClientCard card, int previousControler, int previousLocation, int currentControler, int currentLocation)
{
if (card != null)
{
ClientCard currentSolvingChain = Duel.GetCurrentSolvingChainCard();
if (currentSolvingChain != null && currentLocation == (int)CardLocation.Removed)
{
int originId = card.Id;
if (card.Data != null)
{
if (card.Data.Alias > 0) originId = card.Data.Alias;
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))
if (hint == HintMsg.LinkMaterial)
{
ClientCard monster = Util.GetBestEnemyMonster(false, true);
if (monster != null)
if (AI.HaveSelectedCards()) return null;
List<ClientCard> result = new List<ClientCard>(cards);
List<ClientCard> powerfulMonsters = new List<ClientCard>();
List<ClientCard> lowMonsters = new List<ClientCard>();
foreach (ClientCard card in result)
{
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)
if (card.Level >= 8 || card.LinkCount >= 4 ||
card.Rank >= 8 || card.Attack >= 3000) powerfulMonsters.Add(card);
else lowMonsters.Add(card);
}
lowMonsters.Sort(CardContainer.CompareCardAttack);
powerfulMonsters.Sort(CardContainer.CompareCardAttack);
powerfulMonsters.Reverse();
lowMonsters.AddRange(powerfulMonsters);
return Util.CheckSelectCount(lowMonsters, cards, min, max);
}
if (hint == HintMsg.Destroy)
{
foreach (int id in targetList)
if (AI.HaveSelectedCards()) return null;
//[骰子旋风]破坏对方场上的魔法陷阱
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 (Util.GetLastChainCard().IsCode(id))
if (card == null) continue;
if (!card.HasType(CardType.Spell) && !card.HasType(CardType.Trap))
{
AI.SelectCard(id);
return UniqueFaceupSpell();
}
}
}
return false;
}
/// <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)
{
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;
}
/// <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;
spellCard = false;
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()
{
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;
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>
/// 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))
if (card.Controller == 1) enemyCards.Add(card);
else botCards.Add(card);
}
if (spellCard)
{
enemyCards.AddRange(botCards);
return Util.CheckSelectCount(enemyCards, cards, min, max);
}
}
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 (calledbytheGraveIdCountMap[dic] > 0)
{
calledbytheGraveIdCountMap[dic] -= 1;
}
}
crossoutDesignatorIdList.Clear();
base.OnNewTurn();
}
public override void OnMove(ClientCard card, int previousControler, int previousLocation, int currentControler, int currentLocation)
{
if (card != null)
{
ClientCard currentSolvingChain = Duel.GetCurrentSolvingChainCard();
if (currentSolvingChain != null && currentLocation == (int)CardLocation.Removed)
{
int originId = card.Id;
if (card.Data != null)
{
if (card.Data.Alias > 0) originId = card.Data.Alias;
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();
}
}
}
return false;
}
/// <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)
{
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;
}
/// <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;
if (Bot.LifePoints > Enemy.LifePoints && ActivateDescription == Util.GetStringId(_CardId.ChickenGame, 1))
return true;
......@@ -1623,5 +1760,14 @@ namespace WindBot.Game.AI
}
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.Collections.Generic;
using System.Threading;
using WindBot.Game.AI;
using YGOSharp.OCGWrapper.Enums;
using System;
using System.Threading;
namespace WindBot.Game
{
......@@ -49,9 +50,6 @@ namespace WindBot.Game
public void OnDeckError(string card)
{
_dialogs.SendDeckSorry(card);
Thread.Sleep(1000);
_dialogs.SendSurrender();
Game.Connection.Close();
}
/// <summary>
......@@ -237,10 +235,10 @@ namespace WindBot.Game
if (result != null)
return result;
if (attackers.Count == 0)
if (attackers.Count == 0) //如果自己场上没有可以攻击的怪兽直接返回
return ToMainPhase2();
if (defenders.Count == 0)
if (defenders.Count == 0) //如果对方场上没有怪兽则直接攻击
{
// Attack with the monster with the lowest attack first
ClientCard attacker = attackers[attackers.Count - 1];
......@@ -248,17 +246,17 @@ namespace WindBot.Game
}
else
{
for (int k = 0; k < attackers.Count; ++k)
for (int k = 0; k < attackers.Count; ++k) //如果对方场上有怪兽
{
ClientCard attacker = attackers[k];
attacker.IsLastAttacker = (k == attackers.Count - 1);
result = Executor.OnSelectAttackTarget(attacker, defenders);
result = Executor.OnSelectAttackTarget(attacker, defenders);//这个函数决定是否要攻击
if (result != null)
return result;
}
}
if (!battle.CanMainPhaseTwo)
if (!battle.CanMainPhaseTwo) //如果不能进战阶强制攻击
return Attack(attackers[0], (defenders.Count == 0) ? null : defenders[0]);
return ToMainPhase2();
......@@ -756,7 +754,7 @@ namespace WindBot.Game
sorted.Sort(CardContainer.CompareCardAttack);
IList<ClientCard> selected = new List<ClientCard>();
for (int i = 0; i < min && i < sorted.Count; ++i)
selected.Add(sorted[i]);
......@@ -1174,10 +1172,15 @@ namespace WindBot.Game
if (!Executor.OnPreActivate(card))
return false;
}
bool result = card != null && exec.Type == type &&
(exec.CardId == -1 || exec.CardId == card.Id) &&
(exec.Func == null || exec.Func());
if (card.Id != 0 && type == ExecutorType.Activate && result)
Func<bool> Func = () =>
{
if (Executor.FuncFilters.ContainsKey(exec.Type) && Executor.FuncFilters[exec.Type] != null
&& !Executor.FuncFilters[exec.Type]()) return false;
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;
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