Commit 78fff73f authored by mercury233's avatar mercury233

Merge branch 'master' of https://github.com/IceYGO/windbot

parents 96490bd2 d18e943d
......@@ -15,12 +15,12 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1
uses: microsoft/setup-msbuild@v2
- name: Build!
run: msbuild $env:Solution_Name /t:Build /p:Configuration=Release
......@@ -36,7 +36,7 @@ jobs:
cd ..
- name: Upload build artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
path: dist\WindBot.7z
......@@ -46,7 +46,7 @@ jobs:
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: "latest"
prerelease: true
prerelease: false
title: "Development Build"
files: |
dist/WindBot.7z
......@@ -14,9 +14,19 @@ Random=AI_LV2
一些比较弱的卡组。
SUPPORT_MASTER_RULE_2020
!随机-普通
!随机-一般
Random=AI_LV3
一些环境里可以看到的卡组。
一些不是很弱的卡组。
SUPPORT_MASTER_RULE_2020
!随机-普通
Random=AI_LV4
一些可以(或者曾经可以)在竞技环境里看到的卡组。
SUPPORT_MASTER_RULE_2020
!随机-狂野
Random=AI_WILD
普通的人机的卡组会符合其使用的卡池对应的环境的禁限卡表,但狂野模式的人机的卡组一般不符合任何禁限卡表。
SUPPORT_MASTER_RULE_2020
!随机-报社
......@@ -67,17 +77,17 @@ AI_LV2 SUPPORT_MASTER_RULE_3 SUPPORT_MASTER_RULE_2020
!琪露诺-饼蛙
Name=琪露诺 Deck='Toadally Awesome' Dialog=cirno.zh-CN
大师规则三的全盛饼蛙卡组。
SUPPORT_MASTER_RULE_3 SUPPORT_MASTER_RULE_2020
AI_LV3 SUPPORT_MASTER_RULE_3 SUPPORT_MASTER_RULE_2020
!复制植物-青眼
Name=复制植物 Deck=Blue-Eyes Dialog=copy.zh-CN
青眼卡组。
AI_LV2 SUPPORT_MASTER_RULE_3 SUPPORT_MASTER_RULE_2020
AI_LV3 SUPPORT_MASTER_RULE_3 SUPPORT_MASTER_RULE_2020
!复制植物-十二兽
Name=复制植物 Deck=Zoodiac Dialog=copy.zh-CN
大师规则三的十四兽卡组。
SUPPORT_MASTER_RULE_3 SUPPORT_MASTER_RULE_2020
AI_LV4 SUPPORT_MASTER_RULE_3 SUPPORT_MASTER_RULE_2020
!尼亚-妖仙兽
Name=尼亚 Deck=Yosenju Dialog=near.zh-CN
......@@ -92,17 +102,17 @@ AI_ANTI_META SUPPORT_MASTER_RULE_3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2
!尼亚-淘气仙星
Name=尼亚 Deck=Trickstar Dialog=near.zh-CN
旧式淘气仙星卡组。
AI_LV3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
AI_LV4 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
!尼亚-幻变骚灵
Name=尼亚 Deck=Altergeist Dialog=near.zh-CN
幻变骚灵卡组。
AI_LV3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
AI_LV4 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
!尼亚-拉比林斯迷宫
Name=尼亚 Deck=Labrynth Dialog=near.zh-CN
拉比林斯迷宫卡组。
AI_LV3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
AI_LV4 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
!复制梁龙-闪刀姬
Name=复制梁龙 Deck=SkyStriker Dialog=anothercopy.zh-CN
......@@ -112,7 +122,7 @@ AI_LV3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
!复制梁龙-自奏圣乐
Name=复制梁龙 Deck=Orcust Dialog=anothercopy.zh-CN
旧式自奏圣乐卡组。
AI_LV3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
AI_LV4 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
!复制梁龙-转生炎兽
Name=复制梁龙 Deck=Salamangreat Dialog=anothercopy.zh-CN
......@@ -152,7 +162,7 @@ AI_LV2 SUPPORT_MASTER_RULE_3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
!试作型机器人1732
Name=试作型机器人1732 Deck=ST1732 Dialog=zh-CN
由三盒ST17和三盒SD32组成的卡组。
AI_LV2 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
AI_LV1 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
!奇異果
Name=奇異果 Deck=LightswornShaddoldinosour Dialog=kiwi.zh-TW
......@@ -167,7 +177,7 @@ AI_LV3 SUPPORT_MASTER_RULE_3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
!MAX龍果
Name=MAX龍果 Deck=BlueEyesMaxDragon Dialog=kiwi.zh-TW
青眼混沌极龙卡组。
AI_LV2 SUPPORT_MASTER_RULE_3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
AI_LV3 SUPPORT_MASTER_RULE_3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
!幻煌果
Name=幻煌果 Deck=Phantasm Dialog=kiwi.zh-TW
......@@ -187,54 +197,54 @@ AI_ANTI_META SUPPORT_MASTER_RULE_3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2
!我太帅了-真红眼龙骑士
Name=我太帅了 Deck=Dragun Dialog=smart.zh-CN
超魔导真红眼龙骑士卡组。
AI_LV3 SUPPORT_MASTER_RULE_3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
AI_LV4 SUPPORT_MASTER_RULE_3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
!我太帅了-水百凤凰勇者
Name=我太帅了 Deck=Brave Dialog=smart.zh-CN
水机百头龙凤凰人勇者卡组。
AI_LV3 SUPPORT_MASTER_RULE_2020
AI_LV4 SUPPORT_MASTER_RULE_2020
!玻璃女巫-魔女术
Name=玻璃女巫 Deck=Witchcraft Dialog=verre.zh-CN
魔女术卡组。
AI_LV3 SUPPORT_MASTER_RULE_3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
AI_LV4 SUPPORT_MASTER_RULE_3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
!玻璃女巫-救祓少女
Name=玻璃女巫 Deck=Exosister Dialog=verre.zh-CN
救祓少女卡组。
AI_LV3 SUPPORT_MASTER_RULE_3 SUPPORT_MASTER_RULE_2020
AI_LV4 SUPPORT_MASTER_RULE_3 SUPPORT_MASTER_RULE_2020
!艾克莉西娅-相剑
Name=艾克莉西娅 Deck=Swordsoul Dialog=ecclesia.zh-CN
相剑卡组。
AI_LV3 SUPPORT_MASTER_RULE_3 SUPPORT_MASTER_RULE_2020
AI_LV4 SUPPORT_MASTER_RULE_3 SUPPORT_MASTER_RULE_2020
!艾克莉西娅-教导
Name=艾克莉西娅 Deck=Dogmatika Dialog=ecclesia.zh-CN
教导卡组。
AI_LV3 SUPPORT_MASTER_RULE_3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
AI_LV4 SUPPORT_MASTER_RULE_3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
!神数不神-刹帝利
Name=神数不神 Deck=Kashtira Dialog=Zefra.zh-CN
俱舍怒威族卡组。
AI_LV3 SUPPORT_MASTER_RULE_2020
AI_LV4 SUPPORT_MASTER_RULE_2020
![狂野模式]神数不神-雷龙
![狂野]神数不神-雷龙
Name=神数不神 Deck=ThunderDragon Dialog=Zefra.zh-CN
深渊混沌雷龙卡组。(普通模式的人机的卡组会符合其使用的卡池对应的环境的禁限卡表,但在狂野模式中,人机的卡组不符合任何禁限卡表。)
SUPPORT_MASTER_RULE_2020
深渊混沌雷龙卡组。
AI_WILD SUPPORT_MASTER_RULE_2020
!神数不神-珠泪哀歌
Name=神数不神 Deck=Tearlaments Dialog=Zefra.zh-CN
旧式地天使珠泪哀歌族卡组。
AI_LV3 SUPPORT_MASTER_RULE_2020
AI_LV4 AI_WILD SUPPORT_MASTER_RULE_2020
!神数不神-神数
Name=神数不神 Deck=Zefra Dialog=Zefra.zh-CN
神数卡组。
AI_LV3 SUPPORT_MASTER_RULE_2020
AI_LV4 SUPPORT_MASTER_RULE_2020
!今晚有宵夜吗-超重武者
Name=今晚有宵夜吗 Deck=SuperheavySamurai Dialog=superheavysamurai.zh-CN
超重武者卡组。
AI_LV3 SUPPORT_MASTER_RULE_2020
AI_LV4 SUPPORT_MASTER_RULE_2020
......@@ -64,5 +64,11 @@
"Before you do that, I'll chain {0}!",
"Nice try, but I have {0}!",
"Didn't expect {0}, did you?"
],
"surrender": [
"I surrender.",
"You win this time.",
"I can't win this duel.",
"Good game."
]
}
\ No newline at end of file
......@@ -55,5 +55,10 @@
"但我鸽了",
"无此服务",
"可怕"
],
"surrender": [
"太可怕了(跑路",
"这游戏好难玩(跑路",
"还好我不玩游戏王(跑路"
]
}
......@@ -71,5 +71,9 @@
"我不认同。{0},发动!",
"看样子你忘了我的{0}!",
"你考虑过我有{0}吗?"
],
"surrender": [
"我认输。",
"我承认你的胜利。"
]
}
......@@ -2916,5 +2916,15 @@ namespace WindBot.Game.AI.Decks
}
return base.OnSelectPlace(cardId, player, location, available);
}
protected override bool DefaultSetForDiabellze()
{
if (base.DefaultSetForDiabellze())
{
AI.SelectPlace(SelectSTPlace(Card, true));
return true;
}
return false;
}
}
}
\ No newline at end of file
......@@ -2888,5 +2888,15 @@ namespace WindBot.Game.AI.Decks
return false;
}
protected override bool DefaultSetForDiabellze()
{
if (base.DefaultSetForDiabellze())
{
SelectSTPlace(null, true);
return true;
}
return false;
}
}
}
\ No newline at end of file
......@@ -2976,5 +2976,15 @@ namespace WindBot.Game.AI.Decks
return false;
}
protected override bool DefaultSetForDiabellze()
{
if (base.DefaultSetForDiabellze())
{
SelectSTPlace(null, true);
return true;
}
return false;
}
}
}
\ No newline at end of file
......@@ -3105,5 +3105,14 @@ namespace WindBot.Game.AI.Decks
return false;
}
protected override bool DefaultSetForDiabellze()
{
if (base.DefaultSetForDiabellze())
{
SelectSTPlace(null, true);
return true;
}
return false;
}
}
}
\ No newline at end of file
......@@ -1705,7 +1705,7 @@ namespace WindBot.Game.AI.Decks
if (Duel.Turn == 1 || Enemy.GetMonsterCount() <= 0) return false;
List<ClientCard> e_cards = Enemy.GetMonsters().Where(card => card != null && card.IsFaceup() && card.IsAttack()).ToList();
List<ClientCard> b_cards = Bot.GetMonsters().Where(card => card != null && card.IsFaceup() && card.IsAttack()).ToList();
if ((e_cards.Count <= 0 || b_cards.Count <= 0) && Enemy.MonsterZone.GetDangerousMonster() == null) return false;
if (e_cards.Count <= 0 || b_cards.Count <= 0 || Enemy.MonsterZone.GetDangerousMonster() == null) return false;
e_cards.Sort(CardContainer.CompareCardAttack);
e_cards.Reverse();
b_cards.Sort(CardContainer.CompareCardAttack);
......
......@@ -1823,5 +1823,15 @@ namespace WindBot.Game.AI.Decks
}
return base.OnPreBattleBetween(attacker, defender);
}
protected override bool DefaultSetForDiabellze()
{
if (base.DefaultSetForDiabellze())
{
AI.SelectPlace(SelectSTPlace(Card, true));
return true;
}
return false;
}
}
}
......@@ -2899,5 +2899,15 @@ namespace WindBot.Game.AI.Decks
}
return false;
}
protected override bool DefaultSetForDiabellze()
{
if (base.DefaultSetForDiabellze())
{
SelectSTPlace(null, true);
return true;
}
return false;
}
}
}
\ No newline at end of file
......@@ -192,6 +192,9 @@ namespace WindBot.Game.AI
public const int NovoxTheSilenforcerDisciple = 25801745;
public const int SilenforcingBarrier = 98477480;
public const int DiabellzeOfTheOriginalSin = 53765052;
public const int PotOfExtravagance = 49238328;
}
protected class _Setcode
......@@ -224,6 +227,7 @@ namespace WindBot.Game.AI
AddExecutor(ExecutorType.Activate, _CardId.VaylantzWorld_ShinraBansho, DefaultVaylantzWorld_ShinraBansho);
AddExecutor(ExecutorType.Activate, _CardId.VaylantzWorld_KonigWissen, DefaultVaylantzWorld_KonigWissen);
AddExecutor(ExecutorType.Activate, _CardId.SantaClaws);
AddExecutor(ExecutorType.SpellSet, DefaultSetForDiabellze);
}
protected int lightningStormOption = -1;
......@@ -343,7 +347,7 @@ namespace WindBot.Game.AI
if (defender.IsMonsterDangerous())
{
bool canIgnoreIt = !attacker.IsDisabled() && (
attacker.IsCode(_CardId.UltimateConductorTytanno) && defender.IsDefense() ||
attacker.IsCode(_CardId.UltimateConductorTytanno) && defender.IsDefense() ||
attacker.IsCode(_CardId.ElShaddollConstruct) && defender.IsSpecialSummoned ||
attacker.IsCode(_CardId.AllyOfJusticeCatastor) && !defender.HasAttribute(CardAttribute.Dark));
if (!canIgnoreIt)
......@@ -385,7 +389,7 @@ namespace WindBot.Game.AI
if (attacker.IsMonsterInvincible())
attacker.RealPower = 9999;
if (attacker.EquipCards.Any(equip => equip.IsCode(_CardId.MoonMirrorShield) && !equip.IsDisabled()))
attacker.RealPower = defender.RealPower + 100;
}
......@@ -419,13 +423,13 @@ namespace WindBot.Game.AI
if (defender.OwnTargets.Any(card => card.IsCode(_CardId.PhantomKnightsFogBlade) && !card.IsDisabled()))
return false;
if (defender.HasSetcode(_Setcode.EarthboundImmortal) && !defender.IsDisabled())
return false;
bool attackHighestMonster =
Enemy.HasInMonstersZone(_CardId.RockOfTheVanquisher, true) && Enemy.GetMonsters().Any(card => card.HasSetcode(_Setcode.VanquishSoul)) ||
Enemy.HasInMonstersZone(_CardId.GladiatorBeastDomitianus, true) || Enemy.HasInMonstersZone(_CardId.PatricianOfDarkness) ||
Enemy.HasInMonstersZone(_CardId.RockOfTheVanquisher, true) && Enemy.GetMonsters().Any(card => card.HasSetcode(_Setcode.VanquishSoul)) ||
Enemy.HasInMonstersZone(_CardId.GladiatorBeastDomitianus, true) || Enemy.HasInMonstersZone(_CardId.PatricianOfDarkness) ||
Enemy.HasInMonstersZone(_CardId.DictatorOfD, true) && Enemy.GetMonsters().Any(card => card.HasSetcode(_Setcode.BlueEyes));
if (attackHighestMonster)
{
......@@ -437,16 +441,16 @@ namespace WindBot.Game.AI
if (Enemy.HasInSpellZone(_CardId.SpiralDischarge, true) && Enemy.HasInMonstersZone(_CardId.GaiaTheDragonChampion) && !defender.IsCode(_CardId.GaiaTheDragonChampion))
return false;
if (Enemy.HasInSpellZone(_CardId.CrusadiaVanguard, true) && Enemy.GetMonsters().Any(card => card.HasSetcode(_Setcode.Crusadia) && card.HasType(CardType.Link)) && !defender.HasType(CardType.Link))
return false;
if (defender.IsCode(_CardId.RescueACEHydrant) && !defender.IsDisabled() && Enemy.GetMonsters().Any(monster => monster.HasSetcode(_Setcode.RescueACE) && !monster.IsCode(_CardId.RescueACEHydrant)))
return false;
if (Enemy.HasInSpellZone(_CardId.SilenforcingBarrier, true) && Enemy.HasInMonstersZone(_CardId.NovoxTheSilenforcerDisciple, faceUp: true) && !defender.HasType(CardType.Ritual))
return false;
return true;
}
......@@ -540,7 +544,7 @@ namespace WindBot.Game.AI
extraDeck[shuffleCount] = extraDeck[index];
extraDeck[index] = tempCard;
}
return Util.CheckSelectCount(extraDeck, cards, min, max);
}
......@@ -1580,5 +1584,30 @@ namespace WindBot.Game.AI
return crossoutDesignatorIdList.Contains(cardId)
|| (calledbytheGraveIdCountMap.ContainsKey(cardId) && calledbytheGraveIdCountMap[cardId] > 0);
}
protected virtual bool DefaultSetForDiabellze()
{
if (Card == null) return false;
if (Card.Id == _CardId.PotOfExtravagance) return false;
if (Enemy.HasInMonstersZone(_CardId.DiabellzeOfTheOriginalSin, true, faceUp: true) && Card.HasType(CardType.Spell) && !Card.HasType(CardType.QuickPlay))
{
if (Bot.SpellZone.Any(c => c != null && Duel.MainPhase.ActivableCards.Contains(c) && c.HasType(CardType.Spell) && !Card.HasType(CardType.QuickPlay) && c.IsFacedown()))
{
return false;
}
foreach (CardExecutor exec in Executors)
{
if (exec.Type == ExecutorType.Activate && exec.CardId == Card.Id)
{
if (exec.Func == null || exec.Func())
{
return true;
}
}
}
}
return false;
}
}
}
......@@ -36,6 +36,8 @@ namespace WindBot.Game.AI
[DataMember]
public string[] chaining { get; set; }
[DataMember]
public string[] surrender { get; set; }
[DataMember]
public string[] custom { get; set; }
}
public class Dialogs
......@@ -55,6 +57,7 @@ namespace WindBot.Game.AI
private string[] _summon;
private string[] _setmonster;
private string[] _chaining;
private string[] _surrender;
private string[] _custom;
public Dialogs(GameClient game)
......@@ -78,6 +81,7 @@ namespace WindBot.Game.AI
_summon = data.summon;
_setmonster = data.setmonster;
_chaining = data.chaining;
_surrender = data.surrender;
_custom = data.custom;
}
}
......@@ -162,10 +166,17 @@ namespace WindBot.Game.AI
InternalSendMessage(_chaining, card);
}
public void SendSurrender()
{
InternalSendMessage(_surrender);
}
private void InternalSendMessage(IList<string> array, params object[] opts)
{
if (!_game._chat)
return;
if (array == null || array.Count == 0)
return;
string message = string.Format(array[Program.Rand.Next(array.Count)], opts);
if (message != "")
_game.Chat(message);
......
......@@ -11,6 +11,7 @@
SummonOrSet,
GoToBattlePhase,
GoToMainPhase2,
GoToEndPhase
GoToEndPhase,
Surrender
}
}
\ No newline at end of file
......@@ -25,6 +25,18 @@ namespace WindBot.Game
_activatedCards = new Dictionary<int, int>();
}
private void CheckSurrender()
{
foreach (CardExecutor exec in Executor.Executors)
{
if (exec.Type == ExecutorType.Surrender && exec.Func())
{
_dialogs.SendSurrender();
Game.Surrender();
}
}
}
/// <summary>
/// Called when the AI got the error message.
/// </summary>
......@@ -117,6 +129,7 @@ namespace WindBot.Game
_dialogs.SendNewTurn();
}
Executor.OnNewPhase();
CheckSurrender();
}
public void OnMove(ClientCard card, int previousControler, int previousLocation, int currentControler, int currentLocation)
......@@ -130,6 +143,7 @@ namespace WindBot.Game
public void OnDirectAttack(ClientCard card)
{
_dialogs.SendOnDirectAttack(card.Name);
CheckSurrender();
}
/// <summary>
......@@ -155,6 +169,7 @@ namespace WindBot.Game
m_selector.Clear();
m_selector_pointer = -1;
Executor.OnChainEnd();
CheckSurrender();
}
/// <summary>
......@@ -422,6 +437,7 @@ namespace WindBot.Game
public MainPhaseAction OnSelectIdleCmd(MainPhase main)
{
Executor.SetMain(main);
CheckSurrender();
foreach (CardExecutor exec in Executor.Executors)
{
if (exec.Type == ExecutorType.GoToEndPhase && main.CanEndPhase && exec.Func()) // check if should enter end phase directly
......
......@@ -90,6 +90,11 @@ namespace WindBot.Game
Connection.Send(chat);
}
public void Surrender()
{
Connection.Send(CtosMessage.Surrender);
}
private void OnPacketReceived(BinaryReader reader)
{
_behavior.OnPacket(reader);
......
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