Commit 55b26c72 authored by xiaoye's avatar xiaoye

Merge branch 'dealer-season2' into 'dealer-season2'

发牌姬AI更新

See merge request mycard/windbot!9
parents f5103dc4 53ab0e7a
Pipeline #28959 passed with stage
in 28 seconds
......@@ -5,6 +5,10 @@ using YGOSharp.OCGWrapper.Enums;
using WindBot;
using WindBot.Game;
using WindBot.Game.AI;
using System.Runtime.Remoting.Messaging;
using System.Web.UI;
using static WindBot.Game.AI.Decks.TimeThiefExecutor;
using System.IO;
namespace WindBot.Game.AI
{
......@@ -137,26 +141,85 @@ namespace WindBot.Game.AI
protected DefaultExecutor(GameAI ai, Duel duel)
: base(ai, duel)
{
AddExecutor(ExecutorType.Activate, _CardId.ChickenGame, DefaultChickenGame);
AddExecutor(ExecutorType.Activate, _CardId.ChickenGame, DefaultChickenGame);
AddExecutor(ExecutorType.Activate, _CardId.VaylantzWorld_ShinraBansho, DefaultVaylantzWorld_ShinraBansho);
AddExecutor(ExecutorType.Activate, _CardId.VaylantzWorld_KonigWissen, DefaultVaylantzWorld_KonigWissen);
AddExecutor(ExecutorType.Activate, _CardId.SantaClaws);
AddExecutor(ExecutorType.Activate, DefaultGambleCard);
}
/// <summary>
/// Decide which card should the attacker attack.
/// </summary>
/// <param name="attacker">Card that attack.</param>
/// <param name="defenders">Cards that defend.</param>
/// <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)
DealerMaidenModeAddCardExecutor();//发牌姬行为放到单独函数统一管理
}
void DealerMaidenModeAddCardExecutor()
{
SetFuncFilter(ExecutorType.Activate,()=> {
if (Card.IsCode(5990062)) return Bot.HasInSpellZone(9373534); //[大逆转谜题]只有在自己场上有手里剑覆盖的场合才发动
if(Card.IsCode(3493058)) return Bot.GetSpellCount() + Enemy.GetSpellCount() > 0; //[骰子旋风]玩家场上有魔陷才发动
if(Card.IsCode(22802010)) return Bot.GetMonsterCount() < Enemy.GetMonsterCount(); //[无差别崩坏]自己场上怪兽少于对方才发动
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
};
foreach (int code in codes)
if (Card.IsCode(code)) 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;
}
/// <summary>
/// Decide which card should the attacker attack.
/// </summary>
/// <param name="attacker">Card that attack.</param>
/// <param name="defenders">Cards that defend.</param>
/// <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)
{
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()))
......@@ -322,10 +385,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);
}
......@@ -360,6 +423,24 @@ namespace WindBot.Game.AI
return Util.CheckSelectCount(extraDeck, cards, min, max);
}
if (hint == HintMsg.LinkMaterial)
{
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)
{
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);
}
return null;
}
......@@ -1315,7 +1396,7 @@ namespace WindBot.Game.AI
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
};
foreach(int cardname in cardsname)
if (Card.Id == cardname) return true;
if (Card.IsCode(cardname)) return true;
return false;
}
}
......
......@@ -13,7 +13,8 @@ namespace WindBot.Game.AI
public string Deck { get; set; }
public Duel Duel { get; private set; }
public IList<CardExecutor> Executors { get; private set; }
public GameAI AI { get; private set; }
public Dictionary<ExecutorType, Func<bool>> FuncFilters { get; private set; }
public GameAI AI { get; private set; }
public AIUtil Util { get; private set; }
protected MainPhase Main { get; private set; }
......@@ -33,8 +34,15 @@ namespace WindBot.Game.AI
AI = ai;
Util = new AIUtil(duel);
Executors = new List<CardExecutor>();
Bot = Duel.Fields[0];
FuncFilters = new Dictionary<ExecutorType, Func<bool>>();
FuncFilters.Add(ExecutorType.Summon, null);
FuncFilters.Add(ExecutorType.SpSummon, null);
FuncFilters.Add(ExecutorType.MonsterSet, null);
FuncFilters.Add(ExecutorType.Repos, null);
FuncFilters.Add(ExecutorType.SpellSet, null);
FuncFilters.Add(ExecutorType.Activate, null);
FuncFilters.Add(ExecutorType.SummonOrSet, null);
Bot = Duel.Fields[0];
Enemy = Duel.Fields[1];
}
......@@ -247,10 +255,15 @@ namespace WindBot.Game.AI
CurrentTiming = timing;
}
/// <summary>
/// Do the action for the card if func return true.
/// </summary>
public void AddExecutor(ExecutorType type, int cardId, Func<bool> func)
public void SetFuncFilter(ExecutorType type,Func<bool> func)
{
FuncFilters[type] = func;
}
/// <summary>
/// Do the action for the card if func return true.
/// </summary>
public void AddExecutor(ExecutorType type, int cardId, Func<bool> func)
{
Executors.Add(new CardExecutor(type, cardId, func));
}
......
......@@ -2,6 +2,8 @@
using System.Collections.Generic;
using WindBot.Game.AI;
using YGOSharp.OCGWrapper.Enums;
using System;
using System.Threading;
namespace WindBot.Game
{
......@@ -203,10 +205,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];
......@@ -214,17 +216,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();
......@@ -719,7 +721,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]);
......@@ -1137,9 +1139,17 @@ namespace WindBot.Game
return false;
}
Executor.SetCard(type, card, desc, timing);
bool result = card != null && exec.Type == type &&
Func<bool> Func = () =>
{
bool res = Executor.FuncFilters.ContainsKey(exec.Type) && Executor.FuncFilters[exec.Type] != null;
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) &&
(exec.Func == null || exec.Func());
Func();
if (card.Id != 0 && type == ExecutorType.Activate && result)
{
int count = card.IsDisabled() ? 3 : 1;
......
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