Commit 0974c33d authored by mercury233's avatar mercury233
parents 124f7da2 e85abe26
......@@ -76,18 +76,3 @@
50588353
50588353
!side
67696066
73176465
37742478
15341821
54757758
13529466
74586817
6983839
82633039
46772449
1861629
1845204
53129443
43898403
48130397
{
"welcome": [
"真難得有人發現這個。",
"真沒想到你能跟我對戰呢!決鬥者。不過也就到此為止了,接下來由我V.F.D(非常友善的決鬥者)來做你的對手。"
],
"deckerror": [
"阿,可能BA又把CBD修壞導致{0}消失了。"
],
"duelstart": [
"這只是AI,打贏不要太高興阿。",
"十分致謝233服讓我們有遊戲可以玩,別忘記去拜訪他們。",
"反主流學院請洽NOVA。",
"Wryyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy."
],
"newturn": [
"到我的回合了,抽牌!",
"我的回合,抽牌!",
"我抽了一張卡。"
],
"endturn": [
"回合结束。",
"我的回合结束了。",
"這樣算是成功的展開嗎......",
"輪到你了。你的下一句是......我要發動灰流麗對吧!"
],
"directattack": [
"{0},直接攻擊!",
"{0},直接攻擊對手!",
"{0},没有防守的地方,攻擊!",
"{0},攻擊對手的生命值!",
"{0},直接攻擊對手的生命值!",
"{0},通過直接攻擊打倒對手!",
"{0},使用直接攻擊打倒對手!",
"{0},直接攻擊釋放你的力量吧!",
"我的{0}將會粉碎你的生命值!",
"向對手展示你的力量吧,{0}!",
"你已經無法阻止我了。{0},攻擊!"
],
"attack": [
"{0},攻擊這體{1}!",
"{0},消滅這體{1}!",
"{0},打倒{1}!",
"{0},衝向那體{1}!",
"{0},把你的力量释放到{1}上吧!"
],
"ondirectattack": [
"可惡......",
"不過是{0}而已!",
"果然我還是太弱了......"
],
"facedownmonstername": "怪獸",
"activate": [
"我發動{0}。",
"我使用{0}的效果。",
"我使用{0}的力量。"
],
"summon": [
"真是HIGH的最高點!出來吧{0}。",
"出來吧,{0}!",
"出現吧,{0}!",
"我召喚了強大的{0}!",
"我呼喚{0}參加戰鬥!",
"我呼喚出{0}。",
"我召喚{0}。"
],
"setmonster": [
"我放置了一體怪獸。",
"我裡側表示放置了一體怪獸。"
],
"chaining": [
"看這裡!發動{0}!",
"我使用{0}的力量。",
"很不錯的戰術...但是我拒絕!{0}!",
"真不愧是納粹,竟然能識破我的蓋牌......你說你只是單純的決鬥者?{0},發動!",
"看樣子你忘了我的{0}!",
"你考慮過我有{0}嗎?"
]
}
......@@ -9,8 +9,7 @@
"duelstart": [
"這只是AI,打贏不要太高興阿。",
"十分致謝233服讓我們有遊戲可以玩,別忘記去拜訪他們。",
"反主流學院請洽NOVA。",
"反主流學院請洽NOVA。"
],
"newturn": [
"到我的回合了,抽牌!",
......@@ -71,7 +70,6 @@
"看這裡!發動{0}!",
"我使用{0}的力量。",
"很不錯的戰術...但是我拒絕!{0}!",
"真不愧是納粹,竟然能識破我的蓋牌......你說你只是單純的決鬥者?{0},發動!",
"看樣子你忘了我的{0}!",
"你考慮過我有{0}嗎?"
]
......
using System;
using System;
using System.Collections.Generic;
using YGOSharp.OCGWrapper.Enums;
using WindBot;
......@@ -12,14 +12,15 @@ namespace WindBot.Game.AI
protected class _CardId
{
public const int JizukirutheStarDestroyingKaiju = 63941210;
public const int GadarlatheMysteryDustKaiju = 36956512;
public const int GamecieltheSeaTurtleKaiju = 55063751;
public const int RadiantheMultidimensionalKaiju = 28674152;
public const int KumongoustheStickyStringKaiju = 29726552;
public const int ThunderKingtheLightningstrikeKaiju = 48770333;
public const int DogorantheMadFlameKaiju = 93332803;
public const int RadiantheMultidimensionalKaiju = 28674152;
public const int GadarlatheMysteryDustKaiju = 36956512;
public const int KumongoustheStickyStringKaiju = 29726552;
public const int GamecieltheSeaTurtleKaiju = 55063751;
public const int SuperAntiKaijuWarMachineMechaDogoran = 84769941;
public const int DupeFrog = 46239604;
public const int MaraudingCaptain = 2460565;
......@@ -44,13 +45,40 @@ namespace WindBot.Game.AI
AddExecutor(ExecutorType.Activate, _CardId.ChickenGame, DefaultChickenGame);
}
/// <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)
{
for (int i = 0; i < defenders.Count; ++i)
{
ClientCard defender = defenders[i];
attacker.RealPower = attacker.Attack;
defender.RealPower = defender.GetDefensePower();
if (!OnPreBattleBetween(attacker, defender))
continue;
if (attacker.RealPower > defender.RealPower || (attacker.RealPower >= defender.RealPower && attacker.IsLastAttacker))
return AI.Attack(attacker, defender);
}
if (attacker.CanDirectAttack)
return AI.Attack(attacker, null);
return null;
}
/// <summary>
/// Decide whether to declare attack between attacker and defender.
/// Can be overrided to update the RealPower of attacker for cards like Honest.
/// </summary>
/// <param name="attacker">Card that attack.</param>
/// <param name="defender">Card that defend.</param>
/// <returns>false if the attack can't be done.</returns>
/// <returns>false if the attack shouldn't be done.</returns>
public override bool OnPreBattleBetween(ClientCard attacker, ClientCard defender)
{
if (attacker.RealPower <= 0)
......@@ -68,9 +96,9 @@ namespace WindBot.Game.AI
defender.RealPower = 5000;
if (defender.Id == _CardId.VampireFräulein && !defender.IsDisabled())
defender.RealPower += (Duel.LifePoints[defender.Controller] > 3000) ? 3000 : (Duel.LifePoints[defender.Controller] - 100);
defender.RealPower += (Enemy.LifePoints > 3000) ? 3000 : (Enemy.LifePoints - 100);
if (defender.Id == _CardId.InjectionFairyLily && !defender.IsDisabled() && Duel.LifePoints[defender.Controller] > 2000)
if (defender.Id == _CardId.InjectionFairyLily && !defender.IsDisabled() && Enemy.LifePoints > 2000)
defender.RealPower += 3000;
}
......@@ -99,6 +127,21 @@ namespace WindBot.Game.AI
return true;
}
public override bool OnSelectBattleReplay()
{
if (Bot.BattlingMonster == null)
return false;
List<ClientCard> defenders = new List<ClientCard>(Duel.Fields[1].GetMonsters());
defenders.Sort(AIFunctions.CompareDefensePower);
defenders.Reverse();
BattlePhaseAction result = OnSelectAttackTarget(Bot.BattlingMonster, defenders);
if (result != null && result.Action == BattlePhaseAction.BattleAction.Attack)
{
return true;
}
return false;
}
/// <summary>
/// Destroy face-down cards first, in our turn.
/// </summary>
......@@ -469,6 +512,29 @@ namespace WindBot.Game.AI
return false;
}
/// <summary>
/// Draw when we have Dark monster in hand,and banish random one. Can be overrided.
/// </summary>
protected bool DefaultAllureofDarkness()
{
IList<ClientCard> condition = Bot.Hand;
IList<ClientCard> check = new List<ClientCard>();
ClientCard con = null;
foreach (ClientCard card in condition)
{
if (card.HasAttribute(CardAttribute.Dark))
{
con = card;
break;
}
}
if (con != null)
{
return true;
}
return false;
}
/// <summary>
/// Clever enough.
/// </summary>
......@@ -557,7 +623,7 @@ namespace WindBot.Game.AI
}
/// <summary>
/// Clever enough.
/// Clever enough
/// </summary>
protected bool DefaultInterruptedKaijuSlumber()
{
......@@ -567,24 +633,34 @@ namespace WindBot.Game.AI
{
_CardId.GamecieltheSeaTurtleKaiju,
_CardId.KumongoustheStickyStringKaiju,
_CardId.GadarlatheMysteryDustKaiju,
_CardId.RadiantheMultidimensionalKaiju,
_CardId.GadarlatheMysteryDustKaiju
_CardId.DogorantheMadFlameKaiju,
_CardId.ThunderKingtheLightningstrikeKaiju,
_CardId.JizukirutheStarDestroyingKaiju,
});
return true;
}
AI.SelectCard(new[]
{
_CardId.JizukirutheStarDestroyingKaiju,
_CardId.ThunderKingtheLightningstrikeKaiju,
_CardId.DogorantheMadFlameKaiju,
_CardId.RadiantheMultidimensionalKaiju,
_CardId.GadarlatheMysteryDustKaiju,
_CardId.KumongoustheStickyStringKaiju
_CardId.KumongoustheStickyStringKaiju,
_CardId.GamecieltheSeaTurtleKaiju,
});
AI.SelectNextCard(new[]
{
_CardId.SuperAntiKaijuWarMachineMechaDogoran,
_CardId.GamecieltheSeaTurtleKaiju,
_CardId.KumongoustheStickyStringKaiju,
_CardId.GadarlatheMysteryDustKaiju,
_CardId.RadiantheMultidimensionalKaiju
_CardId.RadiantheMultidimensionalKaiju,
_CardId.DogorantheMadFlameKaiju,
_CardId.ThunderKingtheLightningstrikeKaiju,
});
return DefaultDarkHole();
}
......
......@@ -14,6 +14,7 @@
MetaionTheTimelord = 74530899,
KamionTheTimelord = 91712985,
LazionTheTimelord = 92435533,
EaterOfMillions = 63845230
}
EaterOfMillions = 63845230,
ElShaddollConstruct = 20366274,
}
}
......@@ -52,47 +52,26 @@ namespace WindBot.Game.AI
/// <returns>A new BattlePhaseAction containing the action to do.</returns>
public virtual BattlePhaseAction OnBattle(IList<ClientCard> attackers, IList<ClientCard> defenders)
{
if (attackers.Count == 0)
return AI.ToMainPhase2();
if (defenders.Count == 0)
{
for (int i = attackers.Count - 1; i >= 0; --i)
{
ClientCard attacker = attackers[i];
if (attacker.Attack > 0)
return AI.Attack(attacker, null);
}
}
else
{
for (int i = defenders.Count - 1; i >= 0; --i)
{
ClientCard defender = defenders[i];
for (int j = 0; j < attackers.Count; ++j)
{
ClientCard attacker = attackers[j];
attacker.RealPower = attacker.Attack;
defender.RealPower = defender.GetDefensePower();
if (!OnPreBattleBetween(attacker, defender))
continue;
if (attacker.RealPower > defender.RealPower || (attacker.RealPower >= defender.RealPower && j == attackers.Count - 1))
return AI.Attack(attacker, defender);
}
// For overriding
return null;
}
for (int i = attackers.Count - 1; i >= 0; --i)
/// <summary>
/// Called when the AI has to decide which card to attack first
/// </summary>
/// <param name="attackers">List of monsters that can attcack.</param>
/// <param name="defenders">List of monsters of enemy.</param>
/// <returns>The card to attack first.</returns>
public virtual ClientCard OnSelectAttacker(IList<ClientCard> attackers, IList<ClientCard> defenders)
{
ClientCard attacker = attackers[i];
if (attacker.CanDirectAttack)
return AI.Attack(attacker, null);
}
// For overriding
return null;
}
if (!Battle.CanMainPhaseTwo)
return AI.Attack(attackers[0], (defenders.Count == 0) ? null : defenders[0]);
return AI.ToMainPhase2();
public virtual BattlePhaseAction OnSelectAttackTarget(ClientCard attacker, IList<ClientCard> defenders)
{
// Overrided in DefalultExecutor
return null;
}
public virtual bool OnPreBattleBetween(ClientCard attacker, ClientCard defender)
......@@ -174,6 +153,12 @@ namespace WindBot.Game.AI
return -1;
}
public virtual bool OnSelectBattleReplay()
{
// Overrided in DefalultExecutor
return false;
}
public void SetMain(MainPhase main)
{
Main = main;
......
......@@ -36,6 +36,7 @@ namespace WindBot.Game
public bool CanDirectAttack { get; set; }
public bool ShouldDirectAttack { get; set; }
public bool Attacked { get; set; }
public bool IsLastAttacker { get; set; }
public int[] ActionIndex { get; set; }
public IDictionary<int, int> ActionActivateIndex { get; private set; }
......
......@@ -71,6 +71,19 @@ namespace WindBot.Game
return count;
}
public int GetFieldCount()
{
return GetSpellCount() + GetMonsterCount();
}
public int GetFieldHandCount()
{
return GetSpellCount() + GetMonsterCount() + GetHandCount();
}
public bool IsFieldEmpty()
{
return GetMonsters().Count == 0 && GetSpells().Count == 0;
......
......@@ -143,13 +143,57 @@ namespace WindBot.Game
}
}
// Sort the attackers and defenders, make monster with higher attack go first.
List<ClientCard> attackers = new List<ClientCard>(battle.AttackableCards);
attackers.Sort(AIFunctions.CompareCardAttack);
attackers.Reverse();
List<ClientCard> defenders = new List<ClientCard>(Duel.Fields[1].GetMonsters());
defenders.Sort(AIFunctions.CompareDefensePower);
defenders.Reverse();
return Executor.OnBattle(attackers, defenders);
// Let executor decide which card should attack first.
ClientCard selected = Executor.OnSelectAttacker(attackers, defenders);
if (selected != null && attackers.Contains(selected))
{
attackers.Remove(selected);
attackers.Insert(0, selected);
}
// Check for the executor.
BattlePhaseAction result = Executor.OnBattle(attackers, defenders);
if (result != null)
return result;
if (attackers.Count == 0)
return ToMainPhase2();
if (defenders.Count == 0)
{
// Attack with the monster with the lowest attack first
for (int i = attackers.Count - 1; i >= 0; --i)
{
ClientCard attacker = attackers[i];
if (attacker.Attack > 0)
return Attack(attacker, null);
}
}
else
{
for (int k = 0; k < attackers.Count; ++k)
{
ClientCard attacker = attackers[k];
attacker.IsLastAttacker = (k == attackers.Count - 1);
result = Executor.OnSelectAttackTarget(attacker, defenders);
if (result != null)
return result;
}
}
if (!battle.CanMainPhaseTwo)
return Attack(attackers[0], (defenders.Count == 0) ? null : defenders[0]);
return ToMainPhase2();
}
/// <summary>
......@@ -220,9 +264,11 @@ namespace WindBot.Game
// Always select the first available cards and choose the minimum.
IList<ClientCard> selected = new List<ClientCard>();
if (cards.Count >= min)
{
for (int i = 0; i < min; ++i)
selected.Add(cards[i]);
}
return selected;
}
......@@ -601,6 +647,15 @@ namespace WindBot.Game
return Executor.OnSelectYesNo(desc);
}
/// <summary>
/// Called when the AI has to select if to continue attacking when replay.
/// </summary>
/// <returns>True for yes, false for no.</returns>
public bool OnSelectBattleReplay()
{
return Executor.OnSelectBattleReplay();
}
/// <summary>
/// Called when the AI has to declare a card.
/// </summary>
......
......@@ -108,6 +108,7 @@ namespace WindBot.Game
_messages.Add(GameMessage.BecomeTarget, OnBecomeTarget);
_messages.Add(GameMessage.SelectBattleCmd, OnSelectBattleCmd);
_messages.Add(GameMessage.SelectCard, OnSelectCard);
_messages.Add(GameMessage.SelectUnselectCard, OnSelectUnselectCard);
_messages.Add(GameMessage.SelectChain, OnSelectChain);
_messages.Add(GameMessage.SelectCounter, OnSelectCounter);
_messages.Add(GameMessage.SelectDisfield, OnSelectDisfield);
......@@ -750,11 +751,84 @@ namespace WindBot.Game
Connection.Send(reply);
}
private void InternalOnSelectUnselectCard(BinaryReader packet, Func<IList<ClientCard>, int, int, int, bool, IList<ClientCard>> func)
{
packet.ReadByte(); // player
packet.ReadByte(); // buttonok
bool cancelable = packet.ReadByte() != 0;
int min = packet.ReadByte();
int max = packet.ReadByte();
IList<ClientCard> cards = new List<ClientCard>();
int count = packet.ReadByte();
for (int i = 0; i < count; ++i)
{
int id = packet.ReadInt32();
int player = GetLocalPlayer(packet.ReadByte());
CardLocation loc = (CardLocation)packet.ReadByte();
int seq = packet.ReadByte();
packet.ReadByte(); // pos
ClientCard card;
if (((int)loc & (int)CardLocation.Overlay) != 0)
card = new ClientCard(id, CardLocation.Overlay);
else
card = _duel.GetCard(player, loc, seq);
if (card == null) continue;
if (card.Id == 0)
card.SetId(id);
cards.Add(card);
}
int count2 = packet.ReadByte();
for (int i = 0; i < count2; ++i)
{
int id = packet.ReadInt32();
int player = GetLocalPlayer(packet.ReadByte());
CardLocation loc = (CardLocation)packet.ReadByte();
int seq = packet.ReadByte();
packet.ReadByte(); // pos
}
IList<ClientCard> selected = func(cards, min, max, _select_hint, cancelable);
_select_hint = 0;
if (selected.Count == 0 && cancelable)
{
Connection.Send(CtosMessage.Response, -1);
return;
}
byte[] result = new byte[selected.Count + 1];
result[0] = (byte)selected.Count;
for (int i = 0; i < selected.Count; ++i)
{
int id = 0;
for (int j = 0; j < count; ++j)
{
if (cards[j] == null) continue;
if (cards[j].Equals(selected[i]))
{
id = j;
break;
}
}
result[i + 1] = (byte)id;
}
BinaryWriter reply = GamePacketFactory.Create(CtosMessage.Response);
reply.Write(result);
Connection.Send(reply);
}
private void OnSelectCard(BinaryReader packet)
{
InternalOnSelectCard(packet, _ai.OnSelectCard);
}
private void OnSelectUnselectCard(BinaryReader packet)
{
InternalOnSelectUnselectCard(packet, _ai.OnSelectCard);
}
private void OnSelectChain(BinaryReader packet)
{
packet.ReadByte(); // player
......@@ -1106,7 +1180,12 @@ namespace WindBot.Game
private void OnSelectYesNo(BinaryReader packet)
{
packet.ReadByte(); // player
int reply = _ai.OnSelectYesNo(packet.ReadInt32()) ? (1) : (0);
int desc = packet.ReadInt32();
int reply;
if (desc == 30)
reply = _ai.OnSelectBattleReplay() ? 1 : 0;
else
reply = _ai.OnSelectYesNo(desc) ? 1 : 0;
Connection.Send(CtosMessage.Response, reply);
}
......
using System;
using System;
namespace WindBot
{
......
No preview for this file type
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