Commit b9ed43b0 authored by wind2009's avatar wind2009

Merge remote-tracking branch 'upstream/master' into 2pick

parents 3a410a1f 7d0a5a85
Pipeline #38640 passed with stage
in 1 minute and 23 seconds
......@@ -8,7 +8,7 @@ on:
jobs:
build:
runs-on: windows-2019
runs-on: windows-2022
env:
Solution_Name: WindBot.sln
......
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
</startup>
</configuration>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{0665CA3B-C14F-40EC-ABFB-AD46A695F5A3}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>BotWrapper</RootNamespace>
<AssemblyName>Bot</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject>BotWrapper.BotWrapper</StartupObject>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>WindBot.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="BotWrapper.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="bot.conf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Content Include="WindBot.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{0665CA3B-C14F-40EC-ABFB-AD46A695F5A3}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>BotWrapper</RootNamespace>
<AssemblyName>Bot</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject>BotWrapper.BotWrapper</StartupObject>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>WindBot.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="BotWrapper.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="bot.conf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Content Include="WindBot.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
-->
</Project>
\ No newline at end of file
......@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("IceYGO")]
[assembly: AssemblyProduct("WindBot")]
[assembly: AssemblyCopyright("Copyright © IceYGO 2017")]
[assembly: AssemblyCopyright("Copyright © IceYGO 2015-2025")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
......
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/></startup></configuration>
......@@ -119,6 +119,11 @@ Name=复制梁龙 Deck=Salamangreat Dialog=anothercopy.zh-CN
转生炎兽卡组。
AI_LV3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020
!复制梁龙-雷火沸动
Name=复制梁龙 Deck=Ryzeal Dialog=anothercopy.zh-CN
初代雷火沸动卡组。
AI_LV4 SUPPORT_MASTER_RULE_3 SUPPORT_MASTER_RULE_2020
!VI-1911-凭依装着
Name=VI-1911 Deck=FamiliarPossessed Dialog=VI-1911.zh-CN
凭依装着卡组。
......
#created by ...
#main
32731036
25451383
60242223
62962630
62962630
62962630
68468459
68468459
45484331
45883110
95515789
19096726
14558127
14558127
14558127
23434538
23434538
23434538
36577931
1984618
1984618
6498706
6498706
34995106
44362883
75500286
81439173
24224830
24224830
29948294
36637374
65681983
82738008
18973184
10045474
10045474
10045474
19271881
32756828
17751597
#extra
11321089
38811586
44146295
44146295
92892239
70534340
3410461
24915933
72272462
1906812
41373230
51409648
87746184
87746184
53971455
!side
56787189
55273561
68468460
72554664
95515790
\ No newline at end of file
#created by ...
#main
8633261
8633261
8633261
35844557
35844557
35844557
72238166
34022970
34022970
34022970
42141493
42141493
84192580
87126721
14558127
14558127
14558127
59438930
59438930
23434538
23434538
94145021
97268402
97268402
97268402
7477101
7477101
7477101
25311006
35261759
35261759
85106525
24224830
24224830
60394026
65681983
6798031
10045474
10045474
10045474
#extra
9940036
34909328
34909328
2061963
7511613
7511613
45852939
45852939
6983839
90590303
46772449
16643334
21044178
66011101
8728498
!side
20292186
34267821
34267821
34267821
67173574
18144507
19613556
35269904
15693423
83326048
83326048
83326048
41420027
41420027
41420027
{
"welcome": [
"这里就是大灵峰吗?",
"这里是教导龙国。"
"这里是教导龙国。",
"这里是开放的大地。"
],
"deckerror": [
"{0}被冰水咒缚了!"
......
......@@ -55,28 +55,32 @@ namespace WindBot.Game.AI
{
return cards
.Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget()))
.OrderBy(card => card.Attack).FirstOrDefault();
.OrderByDescending(card => card.Attack)
.FirstOrDefault();
}
public static ClientCard GetHighestDefenseMonster(this IEnumerable<ClientCard> cards, bool canBeTarget = false)
{
return cards
.Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget()))
.OrderBy(card => card.Defense).FirstOrDefault();
.OrderByDescending(card => card.Defense)
.FirstOrDefault();
}
public static ClientCard GetLowestAttackMonster(this IEnumerable<ClientCard> cards, bool canBeTarget = false)
{
return cards
.Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget()))
.OrderByDescending(card => card.Attack).FirstOrDefault();
.OrderBy(card => card.Attack)
.FirstOrDefault();
}
public static ClientCard GetLowestDefenseMonster(this IEnumerable<ClientCard> cards, bool canBeTarget = false)
{
return cards
.Where(card => card?.Data != null && card.HasType(CardType.Monster) && card.IsFaceup() && !(canBeTarget && card.IsShouldNotBeTarget()))
.OrderByDescending(card => card.Defense).FirstOrDefault();
.OrderBy(card => card.Defense)
.FirstOrDefault();
}
public static bool ContainsMonsterWithLevel(this IEnumerable<ClientCard> cards, int level)
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -177,6 +177,22 @@ namespace WindBot.Game.AI.Decks
return null;
}
public override void OnSpSummoned()
{
// not special summoned by chain
if (Duel.GetCurrentSolvingChainCard() == null)
{
foreach (ClientCard card in Duel.LastSummonedCards)
{
if (card.Controller == 0 && card.IsCode(CardId.AlternativeWhiteDragon))
{
AlternativeWhiteDragonSummoned = true;
}
}
}
base.OnSpSummoned();
}
private bool DragonShrineEffect()
{
AI.SelectCard(
......@@ -501,7 +517,6 @@ namespace WindBot.Game.AI.Decks
private bool AlternativeWhiteDragonSummon()
{
AlternativeWhiteDragonSummoned = true;
return true;
}
......
......@@ -1153,8 +1153,8 @@ namespace WindBot.Game.AI.Decks
public override void OnChainSolved(int chainIndex)
{
ClientCard currentCard = Duel.GetCurrentSolvingChainCard();
if (currentCard != null && !Duel.IsCurrentSolvingChainNegated() && currentCard.Controller == 1)
ChainInfo currentCard = Duel.GetCurrentSolvingChainInfo();
if (currentCard != null && !Duel.IsCurrentSolvingChainNegated() && currentCard.ActivatePlayer == 1)
{
if (currentCard.IsCode(_CardId.MaxxC))
enemyActivateMaxxC = true;
......@@ -1166,7 +1166,7 @@ namespace WindBot.Game.AI.Decks
{
for (int i = 0; i < 5; ++i)
{
if (Enemy.SpellZone[i] == currentCard)
if (Enemy.SpellZone[i] == currentCard.RelatedCard)
{
infiniteImpermanenceList.Add(4 - i);
break;
......
......@@ -771,8 +771,8 @@ namespace WindBot.Game.AI.Decks
public override void OnChainSolved(int chainIndex)
{
ClientCard currentCard = Duel.GetCurrentSolvingChainCard();
if (currentCard != null && !Duel.IsCurrentSolvingChainNegated() && currentCard.Controller == 1)
ChainInfo currentCard = Duel.GetCurrentSolvingChainInfo();
if (currentCard != null && !Duel.IsCurrentSolvingChainNegated() && currentCard.ActivatePlayer == 1)
{
if (currentCard.IsCode(_CardId.MaxxC))
enemyActivateMaxxC = true;
......@@ -782,7 +782,7 @@ namespace WindBot.Game.AI.Decks
{
for (int i = 0; i < 5; ++i)
{
if (Enemy.SpellZone[i] == currentCard)
if (Enemy.SpellZone[i] == currentCard.RelatedCard)
{
infiniteImpermanenceList.Add(4 - i);
break;
......
......@@ -153,7 +153,7 @@ namespace WindBot.Game.AI.Decks
{
// We should summon Horus the Black Flame Dragon LV6 if he can lvlup.
if (Enemy.GetMonsterCount() != 0 && !Util.IsAllEnemyBetterThanValue(2300 - 1, false))
foreach (ClientCard card in Main.SummonableCards)
foreach (ClientCard card in Duel.MainPhase.SummonableCards)
if (card.IsCode(11224103))
return false;
......
......@@ -1646,17 +1646,17 @@ namespace WindBot.Game.AI.Decks
public override void OnChainSolved(int chainIndex)
{
ClientCard currentCard = Duel.GetCurrentSolvingChainCard();
ChainInfo currentCard = Duel.GetCurrentSolvingChainInfo();
if (currentCard != null && !Duel.IsCurrentSolvingChainNegated())
{
if (currentCard.Controller == 1)
if (currentCard.ActivatePlayer == 1)
{
if (currentCard.IsCode(_CardId.MaxxC))
enemyActivateMaxxC = true;
if (currentCard.IsCode(CardId.DimensionShifter))
dimensionShifterCount = 2;
}
if (currentCard.Controller == 0)
if (currentCard.ActivatePlayer == 0)
{
if (currentCard.IsCode(CardId.LabrynthCooclock))
cooclockAffected = true;
......
......@@ -69,10 +69,10 @@ namespace WindBot.Game.AI.Decks
if (_lastDoubleSummon == Duel.Turn)
return false;
if (Main.SummonableCards.Count == 0)
if (Duel.MainPhase.SummonableCards.Count == 0)
return false;
if (Main.SummonableCards.Count == 1 && Main.SummonableCards[0].Level < 5)
if (Duel.MainPhase.SummonableCards.Count == 1 && Duel.MainPhase.SummonableCards[0].Level < 5)
{
bool canTribute = false;
foreach (ClientCard handCard in Bot.Hand)
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -80,7 +80,8 @@ namespace WindBot.Game.AI.Decks
public SuperheavySamuraiExecutor(GameAI ai, Duel duel)
: base(ai, duel)
{
AddExecutor(ExecutorType.Activate, CardId.PSYFramelordOmega);
AddExecutor(ExecutorType.Repos, MonsterRepos);
AddExecutor(ExecutorType.Activate, CardId.PSYFramelordOmega,PSYFunction);
AddExecutor(ExecutorType.Activate, CardId.IP,IPFunction);
AddExecutor(ExecutorType.Activate, CardId.Sarutobi,SarutobiFunction);
AddExecutor(ExecutorType.Activate, CardId.Unicorn,UnicornFunction);
......@@ -101,9 +102,8 @@ namespace WindBot.Game.AI.Decks
AddExecutor(ExecutorType.SpSummon, CardId.Scales);
AddExecutor(ExecutorType.Activate, CardId.Scales,ScalesFunction);
//Synchron
AddExecutor(ExecutorType.SpSummon, CardId.ASStardustDragon,ASStardustDragonSynchronFunction2);
AddExecutor(ExecutorType.SpSummon, CardId.Fleur,FleurSynchronFunction2);
//Synchron
AddExecutor(ExecutorType.SpSummon, CardId.PSYFramelordOmega,PSYFramelordOmegaSynchronFunction);
//Pendulum
AddExecutor(ExecutorType.Activate, CardId.Wakaushi,WakaushiFunction);
......@@ -183,7 +183,6 @@ namespace WindBot.Game.AI.Decks
//Synchron
AddExecutor(ExecutorType.SpSummon, CardId.Masurawo,MasurawoSynchronFunction);
AddExecutor(ExecutorType.SpSummon, CardId.Sarutobi,DeSynchronFunction);
AddExecutor(ExecutorType.SpSummon, CardId.PSYFramelordOmega);
//equip Soulhorns
AddExecutor(ExecutorType.Activate, CardId.Soulhorns,SoulhornsEquipFunction);
......@@ -219,6 +218,24 @@ namespace WindBot.Game.AI.Decks
{
return true;
}
private bool MonsterRepos()
{
if (Card.IsFacedown())
return true;
if (Card.IsFaceup() && Card.IsAttack() && (Card.Id == CardId.Masurawo || Card.Id == CardId.Sarutobi))
return true;
return false;
}
public override CardPosition OnSelectPosition(int cardId, IList<CardPosition> positions)
{
YGOSharp.OCGWrapper.NamedCard cardData = YGOSharp.OCGWrapper.NamedCard.Get(cardId);
if (cardData != null)
{
if (cardId == CardId.Masurawo || cardId == CardId.Sarutobi)
return CardPosition.FaceUpDefence;
}
return 0;
}
public override int OnSelectPlace(int cardId, int player, CardLocation location, int available)
{
if (player == 0 && location == CardLocation.MonsterZone)
......@@ -597,14 +614,6 @@ namespace WindBot.Game.AI.Decks
AI.SelectMaterials(materials_lists[0]);
return true;
}
private bool FleurSynchronFunction2()
{
var materials_lists = Util.GetSynchroMaterials(Bot.MonsterZone,10,1,1,false,false,null,
card => { return !FinalCards(card.Id); });
if (materials_lists.Count <= 0) return false;
AI.SelectMaterials(materials_lists[0]);
return true;
}
private bool DeSynchronFunction()
{
AI.SelectPosition(CardPosition.FaceUpDefence);
......@@ -630,17 +639,26 @@ namespace WindBot.Game.AI.Decks
{
return (Bot.HasInExtra(CardId.Fleur) || Bot.HasInExtra(CardId.Masurawo));
}
return false;
}
private bool ASStardustDragonSynchronFunction2()
{
if (!activate_Scales || !activate_PSY) return false;
if (Bot.HasInGraveyard(CardId.Motorbike) || Bot.HasInGraveyard(CardId.PsyFramegearGamma))
else if (Bot.HasInMonstersZone(CardId.Motorbike))
{
return (Bot.HasInExtra(CardId.Fleur) || Bot.HasInExtra(CardId.Masurawo));
AI.SelectMaterials(CardId.Motorbike);
return true;
}
else if (Bot.HasInMonstersZone(CardId.PsyFramegearGamma))
{
AI.SelectMaterials(CardId.PsyFramegearGamma);
return true;
}
return false;
}
private bool PSYFramelordOmegaSynchronFunction()
{
if (Bot.HasInMonstersZone(CardId.Motorbike))
AI.SelectMaterials(CardId.Motorbike);
else if (Bot.HasInMonstersZone(CardId.PsyFramegearGamma))
AI.SelectMaterials(CardId.PsyFramegearGamma);
return activate_PSY || activate_Scales;
}
private bool SavageDragonFunction()
{
if (Duel.LastChainPlayer == 1)
......@@ -1156,6 +1174,11 @@ namespace WindBot.Game.AI.Decks
AI.SelectMaterials(materials);
return true;
}
private bool PSYFunction()
{
activate_PSY = true;
return true;
}
private bool IPFunction()
{
if (Duel.LastChainPlayer == 0) return false;
......@@ -1193,4 +1216,4 @@ namespace WindBot.Game.AI.Decks
return true;
}
}
}
\ No newline at end of file
}
......@@ -695,8 +695,8 @@ namespace WindBot.Game.AI.Decks
public override void OnChainSolved(int chainIndex)
{
ClientCard currentCard = Duel.GetCurrentSolvingChainCard();
if (currentCard != null && !Duel.IsCurrentSolvingChainNegated() && currentCard.Controller == 1)
ChainInfo currentCard = Duel.GetCurrentSolvingChainInfo();
if (currentCard != null && !Duel.IsCurrentSolvingChainNegated() && currentCard.ActivatePlayer == 1)
{
if (currentCard.IsCode(_CardId.MaxxC))
enemyActivateMaxxC = true;
......@@ -706,7 +706,7 @@ namespace WindBot.Game.AI.Decks
{
for (int i = 0; i < 5; ++i)
{
if (Enemy.SpellZone[i] == currentCard)
if (Enemy.SpellZone[i] == currentCard.RelatedCard)
{
infiniteImpermanenceList.Add(4 - i);
break;
......
......@@ -201,8 +201,8 @@ namespace WindBot.Game.AI.Decks
public override void OnChainSolved(int chainIndex)
{
ClientCard currentCard = Duel.GetCurrentSolvingChainCard();
if (currentCard != null && currentCard.Controller == 1)
ChainInfo currentCard = Duel.GetCurrentSolvingChainInfo();
if (currentCard != null && currentCard.ActivatePlayer == 1)
{
if (Duel.IsCurrentSolvingChainNegated())
{
......@@ -212,16 +212,16 @@ namespace WindBot.Game.AI.Decks
if (Bot.MonsterZone.GetFirstMatchingCard(c => c.HasRace(CardRace.SpellCaster) && c.IsFaceup()) != null
&& Bot.HasInSpellZone(CardId.MagicianRightHand, true))
{
Logger.DebugWriteLine("MagicianRightHand negate: " + currentCard.Name ?? "???");
Logger.DebugWriteLine("MagicianRightHand negate: " + currentCard.RelatedCard.Name ?? "???");
MagicianRightHand_used = true;
}
}
if (!MagiciansLeftHand_used && currentCard.IsTrap() && currentCard.Controller == 1)
if (!MagiciansLeftHand_used && currentCard.IsTrap() && currentCard.ActivatePlayer == 1)
{
if (Bot.MonsterZone.GetFirstMatchingCard(c => c.HasRace(CardRace.SpellCaster) && c.IsFaceup()) != null
&& Bot.HasInSpellZone(CardId.MagiciansLeftHand, true))
{
Logger.DebugWriteLine("MagiciansLeftHand negate: " + currentCard.Name ?? "???");
Logger.DebugWriteLine("MagiciansLeftHand negate: " + currentCard.RelatedCard.Name ?? "???");
MagiciansLeftHand_used = true;
}
}
......@@ -236,7 +236,7 @@ namespace WindBot.Game.AI.Decks
{
for (int i = 0; i < 5; ++i)
{
if (Enemy.SpellZone[i] == currentCard)
if (Enemy.SpellZone[i] == currentCard.RelatedCard)
{
Impermanence_list.Add(4 - i);
break;
......
......@@ -99,7 +99,13 @@ namespace WindBot.Game.AI
public const int GhostOgreAndSnowRabbit = 59438930;
public const int GhostBelle = 73642296;
public const int EffectVeiler = 97268402;
public const int GhostMournerMoonlitChill = 52038441;
public const int ArtifactLancea = 34267821;
public const int DimensionShifter = 91800273;
public const int NibiruThePrimalBeing = 27204311;
public const int MulcharmyPurulia = 84192580;
public const int MulcharmyFuwalos = 42141493;
public const int MulcharmyNyalus = 87126721;
public const int CalledByTheGrave = 24224830;
public const int CrossoutDesignator = 65681983;
......@@ -120,9 +126,19 @@ namespace WindBot.Game.AI
public const int ImperialOrder = 61740673;
public const int RoyalDecreel = 51452091;
public const int NaturalExterio = 99916754;
public const int NaturiaBeast = 33198837;
public const int SwordsmanLV7 = 37267041;
public const int AntiSpellFragrance = 58921041;
public const int Number41BagooskatheTerriblyTiredTapir = 90590303;
public const int SkillDrain = 82732705;
public const int DimensionalFissure = 81674782;
public const int BanisheroftheRadiance = 94853057;
public const int BanisheroftheLight = 61528025;
public const int KashtiraAriseHeart = 48626373;
public const int MaskedHERODarkLaw = 58481572;
public const int VaylantzWorld_ShinraBansho = 49568943;
public const int VaylantzWorld_KonigWissen = 75952542;
public const int DivineArsenalAAZEUS_SkyThunder = 90448279;
......@@ -181,6 +197,7 @@ namespace WindBot.Game.AI
public const int DuelDragonToken = 60025884;
public const int SeleneQueenOfTheMasterMagicians = 45819647;
public const int TheWingedDragonofRaSphereMode = 10000080;
public const int SelettriceVaalmonica = 23093373;
public const int RockOfTheVanquisher = 28168628;
public const int SpiralDischarge = 29477860;
......@@ -213,6 +230,7 @@ namespace WindBot.Game.AI
public const int FurHire = 0x114;
public const int Altergeist = 0x103;
public const int Crusadia = 0x116;
public const int Danger = 0x11e;
public const int Endymion = 0x12a;
public const int AncientWarriors = 0x137;
public const int RescueACE = 0x18b;
......@@ -302,7 +320,8 @@ namespace WindBot.Game.AI
{_CardId.DuelLinkDragonTheDuelDragon, (defender, list) => list.Any(monster => monster.IsCode(_CardId.DuelDragonToken))},
{_CardId.SeleneQueenOfTheMasterMagicians, (defender, list) => list.Any(monster => monster.HasSetcode(_Setcode.Endymion))},
{_CardId.TheWingedDragonofRaSphereMode, (defender, list) => true}
{_CardId.TheWingedDragonofRaSphereMode, (defender, list) => true},
{_CardId.SelettriceVaalmonica, (defender, list) => list.Any(monster => !monster.IsCode(_CardId.SelettriceVaalmonica))}
};
/// <summary>
......@@ -778,7 +797,7 @@ namespace WindBot.Game.AI
};
if (Util.GetLastChainCard().IsCode(ignoreList))
return false;
if (Util.GetLastChainCard().HasSetcode(0x11e) && Util.GetLastChainCard().Location == CardLocation.Hand) // Danger! archtype hand effect
if (Util.GetLastChainCard().HasSetcode(_Setcode.Danger) && Util.GetLastChainCard().Location == CardLocation.Hand) // Danger! archtype hand effect
return false;
return Duel.LastChainPlayer == 1;
}
......@@ -1127,6 +1146,15 @@ namespace WindBot.Game.AI
_CardId.EvenlyMatched,
_CardId.DivineArsenalAAZEUS_SkyThunder
};
int[] destroyAllMonsterList =
{
_CardId.DarkHole,
_CardId.InterruptedKaijuSlumber
};
int[] destroyAllOpponentMonsterList =
{
_CardId.Raigeki
};
int[] destroyAllOpponentSpellList =
{
_CardId.HarpiesFeatherDuster,
......@@ -1135,6 +1163,8 @@ namespace WindBot.Game.AI
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)
......@@ -1591,7 +1621,7 @@ namespace WindBot.Game.AI
if (originId == 0) originId = card.Data.Id;
return crossoutDesignatorIdList.Contains(originId)
|| (calledbytheGraveIdCountMap.ContainsKey(originId) && calledbytheGraveIdCountMap[originId] > 0)
|| card.IsDisabled();
|| (card.IsDisabled() && ((int)card.Location & (int)CardLocation.Onfield) > 0);
}
protected bool DefaultCheckWhetherCardIdIsNegated(int cardId)
......@@ -1600,6 +1630,12 @@ namespace WindBot.Game.AI
|| (calledbytheGraveIdCountMap.ContainsKey(cardId) && calledbytheGraveIdCountMap[cardId] > 0);
}
protected int GetCalledbytheGraveIdCount(int cardId)
{
if (!calledbytheGraveIdCountMap.ContainsKey(cardId)) return 0;
return calledbytheGraveIdCountMap[cardId];
}
protected virtual bool DefaultSetForDiabellze()
{
......
......@@ -212,6 +212,17 @@
StellarNemesisTPHON_DoomsdayStar = 93039339,
SPLittleKnight = 29301450,
AngelRing = 40678060,
SkullGuardianTheSilenforcingProtector = 10774240
SkullGuardianProtectorOfTheVoicelessVoice = 10774240,
FloweringEtoileTheMelodiousMagnificat = 83793721,
EnlightenmentDragon = 46186135,
GoldPrideEradicator = 45464587,
VarudrasTheFinalBringerOfTheEndTimes = 70636044,
RagnaraikaStagSovereign = 42307760,
DrytronMeteonisAlphaDraconids = 56863746,
TheUnstoppableExodiaIncarnate = 83257450,
LightAndDarknessDragonLord = 19652159,
FiendsmithDiesIrae = 82135803,
MementomictlanTecuhtlicaCombinedConqueror = 14529511,
MadolcheQueenTiaraalaFraise = 49689480
}
}
......@@ -86,6 +86,8 @@
FusionReproduction = 43331750,
ChimeraFusion = 63136489,
HarmonicSynchroFusion = 7473735,
SouloftheSupremeCelestialKing = 76840111
SouloftheSupremeCelestialKing = 76840111,
MelodiousConcerto = 31458630,
MementotlanFusion = 66518509
}
}
......@@ -114,6 +114,15 @@
DarkGuardian = 26746975,
EnvoyOfTheWaxState = 87462901,
Fluffyfluff = 85401123,
YubelDasEwigLiebeWachter = 47172959
YubelDasEwigLiebeWachter = 47172959,
TenpaiDragonFadra = 65326118,
GolgoilTheSteelSeismicSmasher = 59369430,
TalonsOfShurilane = 74150658,
NightmareApprentice = 58143852,
MillenniumoonMaiden = 37552929,
MillenniumFiendReflection = 63947968,
HereticalPhoboscobos = 76078185,
TopHatHareTheSilhouetteMagician = 1528054,
Silhouhatte = 24440742
}
}
......@@ -11,10 +11,6 @@
SamuraiDestroyer = 40509732,
ArmadesKeeperOfBoundaries = 88033975,
NumberS39UtopiaTheLightning = 56832966,
DualAvatarEmpoweredKonGyo = 33026283,
GGolemRockHammer = 98875863,
WishDragon = 64583600,
ChaosWitch = 30327674,
FissioningMotherSpider = 34034150
DualAvatarEmpoweredKonGyo = 33026283
}
}
......@@ -63,6 +63,10 @@
ThreeEyedGhost = 31464658,
UrsarcticPolarStar = 62714453,
BattlinBoxerPromoter = 83315222,
TGRocketSalamander = 77392987
TGRocketSalamander = 77392987,
GGolemRockHammer = 98875863,
WishDragon = 64583600,
ChaosWitch = 30327674,
FissioningMotherSpider = 34034150
}
}
......@@ -16,6 +16,7 @@
BorreloadDragon = 31833038,
BorrelendDragon = 98630720,
DrytronMeteonisDraconids = 69815951,
MyutantBeast = 34695290
MyutantBeast = 34695290,
VeidosTheDragonOfEndlessDarkness = 8540986
}
}
......@@ -16,9 +16,6 @@ namespace WindBot.Game.AI
public GameAI AI { get; private set; }
public AIUtil Util { get; private set; }
protected MainPhase Main { get; private set; }
protected BattlePhase Battle { get; private set; }
protected ExecutorType Type { get; private set; }
protected ClientCard Card { get; private set; }
protected int ActivateDescription { get; private set; }
......@@ -237,14 +234,14 @@ namespace WindBot.Game.AI
return 0;
}
public void SetMain(MainPhase main)
{
Main = main;
}
public void SetBattle(BattlePhase battle)
/// <summary>
/// Called when card is successfully special summoned.
/// Used on monsters that can only special summoned once per turn.
/// </summary>
public virtual void OnSpSummoned()
{
Battle = battle;
// For overriding
return;
}
/// <summary>
......
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using YGOSharp.OCGWrapper;
using YGOSharp.OCGWrapper.Enums;
namespace WindBot.Game
{
public class ChainInfo
{
public ClientCard RelatedCard { get; private set; }
public int ActivatePlayer { get; private set; }
public int ActivateId { get; private set; }
public int ActivateController { get; private set; }
public int ActivatePosition { get; private set; }
public int ActivateSequence { get; private set; }
public CardLocation ActivateLocation { get; private set; }
public int ActivateLevel { get; private set; }
public int ActivateRank { get; private set; }
public int ActivateType { get; private set; }
public int ActivateRace { get; private set; }
public int ActivateAttack { get; private set; }
public int ActivateDefense { get; private set; }
public bool IsSpecialSummoned { get; private set; }
public int ActivateDescription { get; private set; }
public ChainInfo(ClientCard card)
: this(card, card.Controller, 0)
{
}
public ChainInfo(ClientCard card, int player, int desc)
{
RelatedCard = card;
ActivatePlayer = player;
ActivateId = card.Id;
ActivateController = card.Controller;
ActivatePosition = card.Position;
ActivateSequence = card.Sequence;
ActivateLocation = card.Location;
ActivateLevel = card.Level;
ActivateRank = card.Rank;
ActivateType = card.Type;
ActivateRace = card.Race;
ActivateAttack = card.Attack;
ActivateDefense = card.Defense;
ActivateAttack = card.Attack;
ActivateDefense = card.Defense;
IsSpecialSummoned = card.IsSpecialSummoned;
ActivateDescription = desc;
}
public bool HasPosition(CardPosition position)
{
return (ActivatePosition & (int)position) != 0;
}
public bool HasLocation(CardLocation location)
{
return ((int)ActivateLocation & (int)location) != 0;
}
public bool IsCode(int id)
{
return RelatedCard != null && RelatedCard.IsCode(id);
}
public bool IsCode(IList<int> ids)
{
return RelatedCard != null && RelatedCard.IsCode(ids);
}
public bool IsCode(params int[] ids)
{
return RelatedCard != null && RelatedCard.IsCode(ids);
}
public bool HasType(CardType type)
{
return RelatedCard != null && (RelatedCard.Type & (int)type) != 0;
}
public bool IsSpell()
{
return HasType(CardType.Spell);
}
public bool IsTrap()
{
return HasType(CardType.Trap);
}
}
}
......@@ -82,8 +82,7 @@ namespace WindBot.Game
if (Data != null)
{
Name = Data.Name;
if (Data.Alias != 0)
Alias = Data.Alias;
Alias = Data.Alias;
} else {
Name = null;
Alias = 0;
......@@ -351,6 +350,11 @@ namespace WindBot.Game
return Id == id || Alias - Id < 20 && Alias == id;
}
public bool IsOnField()
{
return Location == CardLocation.MonsterZone || Location == CardLocation.SpellZone || Location == CardLocation.PendulumZone || Location == CardLocation.FieldZone;
}
public bool HasXyzMaterial()
{
return Overlays.Count > 0;
......@@ -387,4 +391,4 @@ namespace WindBot.Game
return ReferenceEquals(this, card);
}
}
}
\ No newline at end of file
}
......@@ -20,6 +20,7 @@ namespace WindBot.Game
public int LastChainPlayer { get; set; }
public CardLocation LastChainLocation { get; set; }
public IList<ClientCard> CurrentChain { get; set; }
public IList<ChainInfo> CurrentChainInfo { get; set; }
public IList<ClientCard> ChainTargets { get; set; }
public IList<ClientCard> LastChainTargets { get; set; }
public IList<ClientCard> ChainTargetOnly { get; set; }
......@@ -37,6 +38,7 @@ namespace WindBot.Game
LastChainPlayer = -1;
LastChainLocation = 0;
CurrentChain = new List<ClientCard>();
CurrentChainInfo = new List<ChainInfo>();
ChainTargets = new List<ClientCard>();
LastChainTargets = new List<ClientCard>();
ChainTargetOnly = new List<ClientCard>();
......@@ -45,6 +47,8 @@ namespace WindBot.Game
LastSummonedCards = new List<ClientCard>();
SolvingChainIndex = 0;
NegatedChainIndexList = new List<int>();
MainPhase = new MainPhase();
BattlePhase = new BattlePhase();
}
public ClientCard GetCard(int player, CardLocation loc, int seq)
......@@ -180,6 +184,12 @@ namespace WindBot.Game
return CurrentChain[SolvingChainIndex - 1];
}
public ChainInfo GetCurrentSolvingChainInfo()
{
if (SolvingChainIndex == 0 || SolvingChainIndex > CurrentChainInfo.Count) return null;
return CurrentChainInfo[SolvingChainIndex - 1];
}
public bool IsCurrentSolvingChainNegated()
{
return SolvingChainIndex > 0 && NegatedChainIndexList.Contains(SolvingChainIndex);
......
using System.Linq;
using System.Collections.Generic;
using System.Threading;
using WindBot.Game.AI;
using YGOSharp.OCGWrapper.Enums;
......@@ -48,6 +49,9 @@ namespace WindBot.Game
public void OnDeckError(string card)
{
_dialogs.SendDeckSorry(card);
Thread.Sleep(1000);
_dialogs.SendSurrender();
Game.Connection.Close();
}
/// <summary>
......@@ -160,6 +164,15 @@ namespace WindBot.Game
{
Executor.OnChainSolved(chainIndex);
}
/// <summary>
/// Called when card is successfully special summoned.
/// Used on monsters that can only special summoned once per turn.
/// </summary>
public void OnSpSummoned()
{
Executor.OnSpSummoned();
}
/// <summary>
/// Called when a chain has been solved.
......@@ -189,7 +202,6 @@ namespace WindBot.Game
/// <returns>A new BattlePhaseAction containing the action to do.</returns>
public BattlePhaseAction OnSelectBattleCmd(BattlePhase battle)
{
Executor.SetBattle(battle);
foreach (CardExecutor exec in Executor.Executors)
{
if (exec.Type == ExecutorType.GoToMainPhase2 && battle.CanMainPhaseTwo && exec.Func()) // check if should enter main phase 2 directly
......@@ -348,7 +360,7 @@ namespace WindBot.Game
/// <param name="forced">You can't return -1 if this param is true.</param>
/// <param name="timing">Current hint timing</param>
/// <returns>Index of the activated card or -1.</returns>
public int OnSelectChain(IList<ClientCard> cards, IList<int> descs, bool forced, int timing = -1)
public int OnSelectChain(IList<ClientCard> cards, IList<int> descs, IList<bool> forces, int timing = -1)
{
Executor.OnSelectChain(cards);
foreach (CardExecutor exec in Executor.Executors)
......@@ -363,8 +375,17 @@ namespace WindBot.Game
}
}
}
// If we're forced to chain, we chain the first card. However don't do anything.
return forced ? 0 : -1;
for (int i = 0; i < forces.Count; ++i)
{
if (forces[i])
{
// If the card is forced, we have to activate it.
_dialogs.SendChaining(cards[i].Name);
return i;
}
}
// Don't do anything.
return -1;
}
/// <summary>
......@@ -436,7 +457,6 @@ namespace WindBot.Game
/// <returns>A new MainPhaseAction containing the action to do.</returns>
public MainPhaseAction OnSelectIdleCmd(MainPhase main)
{
Executor.SetMain(main);
CheckSurrender();
foreach (CardExecutor exec in Executor.Executors)
{
......@@ -1162,6 +1182,7 @@ namespace WindBot.Game
private bool ShouldExecute(CardExecutor exec, ClientCard card, ExecutorType type, int desc = -1, int timing = -1)
{
Executor.SetCard(type, card, desc, timing);
if (card.Id != 0 && type == ExecutorType.Activate)
{
if (_activatedCards.ContainsKey(card.Id) && _activatedCards[card.Id] >= 9)
......@@ -1169,7 +1190,6 @@ namespace WindBot.Game
if (!Executor.OnPreActivate(card))
return false;
}
Executor.SetCard(type, card, desc, timing);
bool result = card != null && exec.Type == type &&
(exec.CardId == -1 || exec.CardId == card.Id) &&
(exec.Func == null || exec.Func());
......
......@@ -30,7 +30,7 @@ namespace WindBot.Game
private Room _room;
private Duel _duel;
private int _hand;
private bool _debug;
private bool _debug;
private int _select_hint;
private GameMessage _lastMessage;
private int lastDuelResult;
......@@ -336,12 +336,10 @@ namespace WindBot.Game
string message = packet.ReadUnicode(256);
string myName = (player != 0) ? _room.Names[1] : _room.Names[0];
string otherName = (player == 0) ? _room.Names[1] : _room.Names[0];
if (_debug) {
if (player < 4)
Logger.WriteLine(otherName + " say to " + myName + ": " + message);
else
Logger.WriteLine("Server say to " + myName + ": " + message);
}
if (player < 4)
Logger.DebugWriteLine(otherName + " say to " + myName + ": " + message);
else
Logger.DebugWriteLine("System message(" + player + "): " + message);
}
private void OnErrorMsg(BinaryReader packet)
......@@ -353,6 +351,7 @@ namespace WindBot.Game
packet.ReadByte();
packet.ReadByte();
int pcode = packet.ReadInt32();
Logger.DebugWriteLine("Error message received: " + msg + ", code: " + pcode);
if (msg == 2) //ERRMSG_DECKERROR
{
int code = pcode & 0xFFFFFFF;
......@@ -431,6 +430,7 @@ namespace WindBot.Game
// in case of ending duel in chain's solving
_duel.CurrentChain.Clear();
_duel.CurrentChainInfo.Clear();
_duel.ChainTargets.Clear();
_duel.ChainTargetOnly.Clear();
_duel.SummoningCards.Clear();
......@@ -819,6 +819,8 @@ namespace WindBot.Game
if (card.Id == 0)
card.SetId(cardId);
int cc = GetLocalPlayer(packet.ReadByte());
packet.ReadInt16(); // trigger location + trigger sequence
int desc = packet.ReadInt32();
if (_debug)
if (card != null) Logger.WriteLine("(" + cc.ToString() + " 's " + (card.Name ?? "UnKnowCard") + " activate effect from " + (CardLocation)pcl + ")");
_duel.LastChainLocation = (CardLocation)pcl;
......@@ -827,6 +829,7 @@ namespace WindBot.Game
_duel.ChainTargetOnly.Clear();
_duel.LastSummonPlayer = -1;
_duel.CurrentChain.Add(card);
_duel.CurrentChainInfo.Add(new ChainInfo(card, cc, desc));
_duel.LastChainPlayer = cc;
}
......@@ -861,6 +864,7 @@ namespace WindBot.Game
_duel.LastChainPlayer = -1;
_duel.LastChainLocation = 0;
_duel.CurrentChain.Clear();
_duel.CurrentChainInfo.Clear();
_duel.ChainTargets.Clear();
_duel.LastChainTargets.Clear();
_duel.ChainTargetOnly.Clear();
......@@ -1072,14 +1076,20 @@ namespace WindBot.Game
packet.ReadByte(); // pos
ClientCard card;
if (((int)loc & (int)CardLocation.Overlay) != 0)
{
card = new ClientCard(id, CardLocation.Overlay, -1);
CardLocation ownerLoc = loc ^ CardLocation.Overlay;
ClientCard ownerCard = _duel.GetCard(player, ownerLoc, seq);
if (ownerCard != null)
card.OwnTargets.Add(ownerCard);
}
else
{
card = _duel.GetCard(player, loc, seq);
card.Controller = player;
}
if (card == null) continue;
if (card.Id == 0)
if (card.Id == 0 || card.Location == CardLocation.Deck)
card.SetId(id);
cards.Add(card);
}
......@@ -1145,7 +1155,7 @@ namespace WindBot.Game
else
card = _duel.GetCard(player, loc, seq);
if (card == null) continue;
if (card.Id == 0)
if (card.Id == 0 || card.Location == CardLocation.Deck)
card.SetId(id);
cards.Add(card);
}
......@@ -1157,6 +1167,14 @@ namespace WindBot.Game
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, -1);
else
card = _duel.GetCard(player, loc, seq);
if (card == null) continue;
if (card.Id == 0 || card.Location == CardLocation.Deck)
card.SetId(id);
}
if (count2 == 0) cancelable = false;
......@@ -1205,16 +1223,19 @@ namespace WindBot.Game
packet.ReadByte(); // player
int count = packet.ReadByte();
packet.ReadByte(); // specount
bool forced = packet.ReadByte() != 0;
int hint1 = packet.ReadInt32(); // hint1
int hint2 = packet.ReadInt32(); // hint2
// TODO: use ChainInfo?
IList<ClientCard> cards = new List<ClientCard>();
IList<int> descs = new List<int>();
IList<bool> forces = new List<bool>();
for (int i = 0; i < count; ++i)
{
packet.ReadByte(); // flag
bool forced = packet.ReadByte() != 0;
int id = packet.ReadInt32();
int con = GetLocalPlayer(packet.ReadByte());
int loc = packet.ReadByte();
......@@ -1233,6 +1254,7 @@ namespace WindBot.Game
cards.Add(card);
descs.Add(desc);
forces.Add(forced);
}
if (cards.Count == 0)
......@@ -1241,13 +1263,13 @@ namespace WindBot.Game
return;
}
if (cards.Count == 1 && forced)
if (cards.Count == 1 && forces[0])
{
Connection.Send(CtosMessage.Response, 0);
return;
}
Connection.Send(CtosMessage.Response, _ai.OnSelectChain(cards, descs, forced, hint1 | hint2));
Connection.Send(CtosMessage.Response, _ai.OnSelectChain(cards, descs, forces, hint1 | hint2));
}
private void OnSelectCounter(BinaryReader packet)
......@@ -1631,6 +1653,11 @@ namespace WindBot.Game
int OpParam = packet.ReadInt32();
int OpParam1 = OpParam & 0xffff;
int OpParam2 = OpParam >> 16;
if ((OpParam & 0x80000000) > 0)
{
OpParam1 = OpParam & 0x7fffffff;
OpParam2 = 0;
}
if (OpParam2 > 0 && OpParam1 > OpParam2)
{
card.OpParam1 = OpParam2;
......@@ -2018,12 +2045,14 @@ namespace WindBot.Game
card.IsSpecialSummoned = true;
_duel.LastSummonedCards.Add(card);
}
_ai.OnSpSummoned();
_duel.SummoningCards.Clear();
}
private void OnConfirmCards(BinaryReader packet)
{
/*int playerid = */packet.ReadByte();
/*int skip_panel = */packet.ReadByte();
int count = packet.ReadByte();
for (int i = 0; i < count; ++ i)
{
......
using System.IO;
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using YGOSharp.Network;
using YGOSharp.Network.Enums;
using YGOSharp.Network.Utils;
......@@ -67,7 +67,12 @@ namespace WindBot.Game
private void OnConnected()
{
BinaryWriter packet = GamePacketFactory.Create(CtosMessage.PlayerInfo);
BinaryWriter packet = GamePacketFactory.Create(CtosMessage.ExternalAddress);
packet.Write((UInt32)0); // real_ip, is always 0 in normal client
packet.WriteUnicodeAutoLength(_serverHost, 255);
Connection.Send(packet);
packet = GamePacketFactory.Create(CtosMessage.PlayerInfo);
packet.WriteUnicode(Username, 20);
Connection.Send(packet);
......@@ -75,7 +80,7 @@ namespace WindBot.Game
packet = GamePacketFactory.Create(CtosMessage.JoinGame);
packet.Write(_proVersion);
packet.Write(junk);
packet.WriteUnicode(_roomInfo, 30);
packet.WriteUnicode(_roomInfo, 20);
Connection.Send(packet);
}
......@@ -86,9 +91,8 @@ namespace WindBot.Game
public void Chat(string message)
{
byte[] content = Encoding.Unicode.GetBytes(message + "\0");
BinaryWriter chat = GamePacketFactory.Create(CtosMessage.Chat);
chat.Write(content);
chat.WriteUnicodeAutoLength(message, 255);
Connection.Send(chat);
}
......
......@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("IceYGO")]
[assembly: AssemblyProduct("WindBot")]
[assembly: AssemblyCopyright("Copyright © IceYGO 2015-2017")]
[assembly: AssemblyCopyright("Copyright © IceYGO 2015-2025")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
......
# WindBot
A C# bot for YGOPro, compatible with the [YGOSharp](https://github.com/IceYGO/ygosharp) and [SRVPro](https://github.com/moecube/srvpro) server.
A C# bot for [YGOPro](https://github.com/Fluorohydride/ygopro), compatible with the [YGOSharp](https://github.com/IceYGO/ygosharp) and [SRVPro](https://github.com/mycard/srvpro) server.
### How to use:
......@@ -139,10 +139,13 @@ WindBot can run as a "server", provide a http interface to create bot.
* Nekroz
### AI Template Generator
### Template Generator
A Java program which generate executor code from deck, made by Levyaton.
https://github.com/Levyaton/WindbotTemplateGenerator
A tool which generates a WindBot deck code template from a YGOPro deck file.
You can use it to create a new deck for WindBot quickly.
https://mercury233.me/windbot/gen.html
### Server mode
......@@ -154,6 +157,11 @@ In this situation, it will be multi-threaded. This can be useful for servers, si
The parameters are same as commandlines, but low cased.
Note: Currently the server bind to all interfaces, so it requires elevated privileges to run. You can otherwise use the following command to add a URL ACL for your port (2399 for example), which allows all users to access it:
```
netsh http add urlacl url=http://+:2399/ user=Everyone
```
### Known issues
* If one chain includes two activation that use `AI.SelectCard`, the second one won't select correctly.
......
......@@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>WindBot</RootNamespace>
<AssemblyName>WindBot</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
......@@ -21,6 +21,7 @@
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\Release\</OutputPath>
......@@ -30,9 +31,10 @@
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
<StartupObject>WindBot.Program</StartupObject>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>WindBot.ico</ApplicationIcon>
......@@ -40,6 +42,12 @@
<PropertyGroup>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Data.Sqlite">
<HintPath>.\Mono.Data.Sqlite.dll</HintPath>
......@@ -60,6 +68,8 @@
<Compile Include="Game\AI\CardSelector.cs" />
<Compile Include="Game\AI\DeckAttribute.cs" />
<Compile Include="Game\AI\DecksManager.cs" />
<Compile Include="Game\AI\Decks\RyzealExecutor.cs" />
<Compile Include="Game\AI\Decks\AlbazExecutor.cs" />
<Compile Include="Game\AI\Decks\AltergeistExecutor.cs" />
<Compile Include="Game\AI\Decks\BraveExecutor.cs" />
<Compile Include="Game\AI\Decks\FamiliarPossessedExecutor.cs" />
......@@ -135,6 +145,7 @@
<Compile Include="Game\AI\ExecutorType.cs" />
<Compile Include="Game\BattlePhase.cs" />
<Compile Include="Game\BattlePhaseAction.cs" />
<Compile Include="Game\ChainInfo.cs" />
<Compile Include="Game\ClientCard.cs" />
<Compile Include="Game\ClientField.cs" />
<Compile Include="Game\Deck.cs" />
......
......@@ -26,7 +26,7 @@ namespace WindBot
Host = "127.0.0.1";
Port = 7911;
HostInfo = "";
Version = 0x1361;
Version = 0x1362;
Hand = 0;
Debug = false;
Chat = true;
......
......@@ -13,6 +13,7 @@
Surrender = 0x14,
TimeConfirm = 0x15,
Chat = 0x16,
ExternalAddress = 0x17,
HsToDuelist = 0x20,
HsToObserver = 0x21,
HsReady = 0x22,
......
......@@ -6,15 +6,40 @@ namespace YGOSharp.Network.Utils
{
public static class BinaryExtensions
{
// fixed length strings
public static void WriteUnicode(this BinaryWriter writer, string text, int len)
{
byte[] unicode = Encoding.Unicode.GetBytes(text);
byte[] result = new byte[len * 2];
int max = len * 2 - 2;
Array.Copy(unicode, result, unicode.Length > max ? max : unicode.Length);
int copy = unicode.Length;
if (unicode.Length > len * 2 - 2)
{
copy = len * 2 - 2;
#if DEBUG
throw new ArgumentException("String '" + text + "' is too long for fixed length " + len + ".");
#endif
}
Array.Copy(unicode, result, copy);
writer.Write(result);
}
// variable length strings
public static void WriteUnicodeAutoLength(this BinaryWriter writer, string text, int maxlen)
{
byte[] result = Encoding.Unicode.GetBytes(text + "\0");
int len = result.Length / 2;
if (len > maxlen)
{
len = maxlen;
result[len * 2 - 2] = 0;
result[len * 2 - 1] = 0;
#if DEBUG
throw new ArgumentException("String '" + text + "' is too long for max length " + maxlen + ".");
#endif
}
writer.Write(result, 0, len * 2);
}
public static string ReadUnicode(this BinaryReader reader, int len)
{
byte[] unicode = reader.ReadBytes(len * 2);
......
......@@ -17,7 +17,7 @@
Thunder = 0x1000,
Dragon = 0x2000,
Beast = 0x4000,
BestWarrior = 0x8000,
BeastWarrior = 0x8000,
Dinosaur = 0x10000,
Fish = 0x20000,
SeaSerpent = 0x40000,
......
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