Commit 30b4ece3 authored by nanahira's avatar nanahira

Merge branch 'develop'

parents 56cbdb31 2a167492
...@@ -8,7 +8,7 @@ on: ...@@ -8,7 +8,7 @@ on:
jobs: jobs:
build: build:
runs-on: windows-2019 runs-on: windows-2022
env: env:
Solution_Name: WindBot.sln Solution_Name: WindBot.sln
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
</startup> </startup>
</configuration> </configuration>
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <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')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{0665CA3B-C14F-40EC-ABFB-AD46A695F5A3}</ProjectGuid> <ProjectGuid>{0665CA3B-C14F-40EC-ABFB-AD46A695F5A3}</ProjectGuid>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>BotWrapper</RootNamespace> <RootNamespace>BotWrapper</RootNamespace>
<AssemblyName>Bot</AssemblyName> <AssemblyName>Bot</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86'"> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath> <OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> <Prefer32Bit>false</Prefer32Bit>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86'"> </PropertyGroup>
<PlatformTarget>x86</PlatformTarget> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86'">
<DebugType>pdbonly</DebugType> <PlatformTarget>x86</PlatformTarget>
<Optimize>true</Optimize> <DebugType>pdbonly</DebugType>
<OutputPath>bin\Release\</OutputPath> <Optimize>true</Optimize>
<DefineConstants>TRACE</DefineConstants> <OutputPath>bin\Release\</OutputPath>
<ErrorReport>prompt</ErrorReport> <DefineConstants>TRACE</DefineConstants>
<WarningLevel>4</WarningLevel> <ErrorReport>prompt</ErrorReport>
</PropertyGroup> <WarningLevel>4</WarningLevel>
<PropertyGroup> <Prefer32Bit>false</Prefer32Bit>
<StartupObject>BotWrapper.BotWrapper</StartupObject> </PropertyGroup>
</PropertyGroup> <PropertyGroup>
<PropertyGroup> <StartupObject>BotWrapper.BotWrapper</StartupObject>
<ApplicationIcon>WindBot.ico</ApplicationIcon> </PropertyGroup>
</PropertyGroup> <PropertyGroup>
<ItemGroup> <ApplicationIcon>WindBot.ico</ApplicationIcon>
<Reference Include="System" /> </PropertyGroup>
<Reference Include="System.Data" /> <ItemGroup>
<Reference Include="System.Xml" /> <Reference Include="System" />
</ItemGroup> <Reference Include="System.Data" />
<ItemGroup> <Reference Include="System.Xml" />
<Compile Include="BotWrapper.cs" /> </ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" /> <ItemGroup>
</ItemGroup> <Compile Include="BotWrapper.cs" />
<ItemGroup> <Compile Include="Properties\AssemblyInfo.cs" />
<None Include="app.config" /> </ItemGroup>
<None Include="bot.conf"> <ItemGroup>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <None Include="app.config" />
</None> <None Include="bot.conf">
</ItemGroup> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ItemGroup> </None>
<Content Include="WindBot.ico" /> </ItemGroup>
</ItemGroup> <ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <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. <!-- 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. Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild"> <Target Name="BeforeBuild">
</Target> </Target>
<Target Name="AfterBuild"> <Target Name="AfterBuild">
</Target> </Target>
--> -->
</Project> </Project>
\ No newline at end of file
...@@ -10,7 +10,7 @@ using System.Runtime.InteropServices; ...@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("IceYGO")] [assembly: AssemblyCompany("IceYGO")]
[assembly: AssemblyProduct("WindBot")] [assembly: AssemblyProduct("WindBot")]
[assembly: AssemblyCopyright("Copyright © IceYGO 2017")] [assembly: AssemblyCopyright("Copyright © IceYGO 2015-2025")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration> <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/></startup></configuration>
...@@ -2186,7 +2186,7 @@ namespace WindBot.Game.AI.Decks ...@@ -2186,7 +2186,7 @@ namespace WindBot.Game.AI.Decks
public override int OnSelectOption(IList<int> options) public override int OnSelectOption(IList<int> options)
{ {
ClientCard currentSolvingChain = Duel.GetCurrentSolvingChainCard(); ChainInfo currentSolvingChain = Duel.GetCurrentSolvingChainInfo();
if (currentSolvingChain != null) if (currentSolvingChain != null)
{ {
// 1190=Add to Hand, 1152=Special Summon // 1190=Add to Hand, 1152=Special Summon
...@@ -2246,8 +2246,8 @@ namespace WindBot.Game.AI.Decks ...@@ -2246,8 +2246,8 @@ namespace WindBot.Game.AI.Decks
public override int OnSelectPlace(int cardId, int player, CardLocation location, int available) public override int OnSelectPlace(int cardId, int player, CardLocation location, int available)
{ {
ClientCard currentSovingChain = Duel.GetCurrentSolvingChainCard(); ChainInfo currentSovingChain = Duel.GetCurrentSolvingChainInfo();
if (currentSovingChain != null && currentSovingChain.Controller == 0 && currentSovingChain.IsCode(CardId.SprindTheIrondashDragon)) if (currentSovingChain != null && currentSovingChain.ActivatePlayer == 0 && currentSovingChain.IsCode(CardId.SprindTheIrondashDragon))
{ {
return SprindTheIrondashDragonMoveZone(available, null); return SprindTheIrondashDragonMoveZone(available, null);
} }
...@@ -2435,21 +2435,21 @@ namespace WindBot.Game.AI.Decks ...@@ -2435,21 +2435,21 @@ namespace WindBot.Game.AI.Decks
public override void OnChainSolved(int chainIndex) public override void OnChainSolved(int chainIndex)
{ {
ClientCard currentCard = Duel.GetCurrentSolvingChainCard(); ChainInfo currentCard = Duel.GetCurrentSolvingChainInfo();
if (currentCard != null) if (currentCard != null)
{ {
// if activation is negated, it can activate again. // if activation is negated, it can activate again.
if (currentCard.Controller == 0) if (currentCard.ActivatePlayer == 0)
{ {
List<int> activateCheck = new List<int> { CardId.NadirServant, CardId.FusionDeployment, CardId.BrandedFusion, CardId.BrandedInRed }; List<int> activateCheck = new List<int> { CardId.NadirServant, CardId.FusionDeployment, CardId.BrandedFusion, CardId.BrandedInRed };
if (currentCard.IsCode(activateCheck)) if (currentCard.IsCode(activateCheck))
{ {
activatedCardIdList.Add(currentCard.Id); activatedCardIdList.Add(currentCard.ActivateId);
} }
} }
if (!Duel.IsCurrentSolvingChainNegated()) if (!Duel.IsCurrentSolvingChainNegated())
{ {
if (currentCard.Controller == 1) if (currentCard.ActivatePlayer == 1)
{ {
if (currentCard.IsCode(_CardId.MaxxC)) if (currentCard.IsCode(_CardId.MaxxC))
enemyActivateMaxxC = true; enemyActivateMaxxC = true;
...@@ -2458,7 +2458,7 @@ namespace WindBot.Game.AI.Decks ...@@ -2458,7 +2458,7 @@ namespace WindBot.Game.AI.Decks
if (currentCard.IsCode(CardId.DimensionShifter)) if (currentCard.IsCode(CardId.DimensionShifter))
dimensionShifterCount = 2; dimensionShifterCount = 2;
} }
if (currentCard.Controller == 0 && currentCard.IsCode(CardId.NadirServant)) if (currentCard.ActivatePlayer == 0 && currentCard.IsCode(CardId.NadirServant))
{ {
nadirActivated = true; nadirActivated = true;
} }
......
...@@ -1153,8 +1153,8 @@ namespace WindBot.Game.AI.Decks ...@@ -1153,8 +1153,8 @@ namespace WindBot.Game.AI.Decks
public override void OnChainSolved(int chainIndex) public override void OnChainSolved(int chainIndex)
{ {
ClientCard currentCard = Duel.GetCurrentSolvingChainCard(); ChainInfo currentCard = Duel.GetCurrentSolvingChainInfo();
if (currentCard != null && !Duel.IsCurrentSolvingChainNegated() && currentCard.Controller == 1) if (currentCard != null && !Duel.IsCurrentSolvingChainNegated() && currentCard.ActivatePlayer == 1)
{ {
if (currentCard.IsCode(_CardId.MaxxC)) if (currentCard.IsCode(_CardId.MaxxC))
enemyActivateMaxxC = true; enemyActivateMaxxC = true;
...@@ -1166,7 +1166,7 @@ namespace WindBot.Game.AI.Decks ...@@ -1166,7 +1166,7 @@ namespace WindBot.Game.AI.Decks
{ {
for (int i = 0; i < 5; ++i) for (int i = 0; i < 5; ++i)
{ {
if (Enemy.SpellZone[i] == currentCard) if (Enemy.SpellZone[i] == currentCard.RelatedCard)
{ {
infiniteImpermanenceList.Add(4 - i); infiniteImpermanenceList.Add(4 - i);
break; break;
......
...@@ -771,8 +771,8 @@ namespace WindBot.Game.AI.Decks ...@@ -771,8 +771,8 @@ namespace WindBot.Game.AI.Decks
public override void OnChainSolved(int chainIndex) public override void OnChainSolved(int chainIndex)
{ {
ClientCard currentCard = Duel.GetCurrentSolvingChainCard(); ChainInfo currentCard = Duel.GetCurrentSolvingChainInfo();
if (currentCard != null && !Duel.IsCurrentSolvingChainNegated() && currentCard.Controller == 1) if (currentCard != null && !Duel.IsCurrentSolvingChainNegated() && currentCard.ActivatePlayer == 1)
{ {
if (currentCard.IsCode(_CardId.MaxxC)) if (currentCard.IsCode(_CardId.MaxxC))
enemyActivateMaxxC = true; enemyActivateMaxxC = true;
...@@ -782,7 +782,7 @@ namespace WindBot.Game.AI.Decks ...@@ -782,7 +782,7 @@ namespace WindBot.Game.AI.Decks
{ {
for (int i = 0; i < 5; ++i) for (int i = 0; i < 5; ++i)
{ {
if (Enemy.SpellZone[i] == currentCard) if (Enemy.SpellZone[i] == currentCard.RelatedCard)
{ {
infiniteImpermanenceList.Add(4 - i); infiniteImpermanenceList.Add(4 - i);
break; break;
......
...@@ -153,7 +153,7 @@ namespace WindBot.Game.AI.Decks ...@@ -153,7 +153,7 @@ namespace WindBot.Game.AI.Decks
{ {
// We should summon Horus the Black Flame Dragon LV6 if he can lvlup. // We should summon Horus the Black Flame Dragon LV6 if he can lvlup.
if (Enemy.GetMonsterCount() != 0 && !Util.IsAllEnemyBetterThanValue(2300 - 1, false)) 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)) if (card.IsCode(11224103))
return false; return false;
......
...@@ -1646,17 +1646,17 @@ namespace WindBot.Game.AI.Decks ...@@ -1646,17 +1646,17 @@ namespace WindBot.Game.AI.Decks
public override void OnChainSolved(int chainIndex) public override void OnChainSolved(int chainIndex)
{ {
ClientCard currentCard = Duel.GetCurrentSolvingChainCard(); ChainInfo currentCard = Duel.GetCurrentSolvingChainInfo();
if (currentCard != null && !Duel.IsCurrentSolvingChainNegated()) if (currentCard != null && !Duel.IsCurrentSolvingChainNegated())
{ {
if (currentCard.Controller == 1) if (currentCard.ActivatePlayer == 1)
{ {
if (currentCard.IsCode(_CardId.MaxxC)) if (currentCard.IsCode(_CardId.MaxxC))
enemyActivateMaxxC = true; enemyActivateMaxxC = true;
if (currentCard.IsCode(CardId.DimensionShifter)) if (currentCard.IsCode(CardId.DimensionShifter))
dimensionShifterCount = 2; dimensionShifterCount = 2;
} }
if (currentCard.Controller == 0) if (currentCard.ActivatePlayer == 0)
{ {
if (currentCard.IsCode(CardId.LabrynthCooclock)) if (currentCard.IsCode(CardId.LabrynthCooclock))
cooclockAffected = true; cooclockAffected = true;
......
...@@ -69,10 +69,10 @@ namespace WindBot.Game.AI.Decks ...@@ -69,10 +69,10 @@ namespace WindBot.Game.AI.Decks
if (_lastDoubleSummon == Duel.Turn) if (_lastDoubleSummon == Duel.Turn)
return false; return false;
if (Main.SummonableCards.Count == 0) if (Duel.MainPhase.SummonableCards.Count == 0)
return false; 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; bool canTribute = false;
foreach (ClientCard handCard in Bot.Hand) foreach (ClientCard handCard in Bot.Hand)
......
...@@ -64,6 +64,7 @@ namespace WindBot.Game.AI.Decks ...@@ -64,6 +64,7 @@ namespace WindBot.Game.AI.Decks
AddExecutor(ExecutorType.Activate, _CardId.GhostOgreAndSnowRabbit, GhostOgreAndSnowRabbitActivate); AddExecutor(ExecutorType.Activate, _CardId.GhostOgreAndSnowRabbit, GhostOgreAndSnowRabbitActivate);
AddExecutor(ExecutorType.Activate, _CardId.AshBlossom, AshBlossomActivate); AddExecutor(ExecutorType.Activate, _CardId.AshBlossom, AshBlossomActivate);
AddExecutor(ExecutorType.Activate, CardId.RyzealCross, RyzealCrossActivateCard);
AddExecutor(ExecutorType.Activate, _CardId.EvilswarmExcitonKnight, EvilswarmExcitonKnightActivate); AddExecutor(ExecutorType.Activate, _CardId.EvilswarmExcitonKnight, EvilswarmExcitonKnightActivate);
AddExecutor(ExecutorType.Activate, CardId.RyzealDeadnader, RyzealDeadnaderActivate); AddExecutor(ExecutorType.Activate, CardId.RyzealDeadnader, RyzealDeadnaderActivate);
AddExecutor(ExecutorType.Activate, CardId.RyzealDuodrive, RyzealDuodriveActivate); AddExecutor(ExecutorType.Activate, CardId.RyzealDuodrive, RyzealDuodriveActivate);
...@@ -82,7 +83,6 @@ namespace WindBot.Game.AI.Decks ...@@ -82,7 +83,6 @@ namespace WindBot.Game.AI.Decks
AddExecutor(ExecutorType.Activate, CardId.Bonfire, BonfireActivate); AddExecutor(ExecutorType.Activate, CardId.Bonfire, BonfireActivate);
AddExecutor(ExecutorType.Activate, CardId.DonnerDaggerFurHire, DonnerDaggerFurHireActivate); AddExecutor(ExecutorType.Activate, CardId.DonnerDaggerFurHire, DonnerDaggerFurHireActivate);
AddExecutor(ExecutorType.Activate, CardId.Number60DugaresTheTimeless, Number60DugaresTheTimelessActivate); AddExecutor(ExecutorType.Activate, CardId.Number60DugaresTheTimeless, Number60DugaresTheTimelessActivate);
AddExecutor(ExecutorType.Activate, CardId.RyzealCross, RyzealCrossActivateCard);
AddExecutor(ExecutorType.Activate, CardId.TripleTacticsTalent, TripleTacticsTalentActivate); AddExecutor(ExecutorType.Activate, CardId.TripleTacticsTalent, TripleTacticsTalentActivate);
AddExecutor(ExecutorType.Activate, CardId.Bonfire, BonfireActivateToSearchNecessary); AddExecutor(ExecutorType.Activate, CardId.Bonfire, BonfireActivateToSearchNecessary);
AddExecutor(ExecutorType.Activate, CardId.SeventhTachyon, SeventhTachyonActivate); AddExecutor(ExecutorType.Activate, CardId.SeventhTachyon, SeventhTachyonActivate);
...@@ -372,6 +372,26 @@ namespace WindBot.Game.AI.Decks ...@@ -372,6 +372,26 @@ namespace WindBot.Game.AI.Decks
return true; return true;
} }
public bool CheckCardShouldNegate(ChainInfo chainInfo)
{
if (chainInfo == null) return false;
ClientCard card = chainInfo.RelatedCard;
if (card == null) return false;
if (card.IsMonster() && card.HasSetcode(SetcodeTimeLord) && Duel.Phase == DuelPhase.Standby) return false;
if (NotToNegateIdList.Contains(card.Id)) return false;
if (card.HasSetcode(_Setcode.Danger) && card.Location == CardLocation.Hand) return false;
if (card.IsMonster() && chainInfo.HasLocation(CardLocation.MonsterZone) && chainInfo.HasPosition(CardPosition.Defence))
{
if (Enemy.MonsterZone.Any(c => CheckNumber41(c)) || Bot.MonsterZone.Any(c => CheckNumber41(c))) return false;
}
if (DefaultCheckWhetherCardIsNegated(card)) return false;
if (Duel.Player == 1 && card.IsCode(_CardId.MulcharmyPurulia, _CardId.MulcharmyFuwalos, _CardId.MulcharmyNyalus)) return false;
if (card.IsDisabled()) return false;
return true;
}
/// <summary> /// <summary>
/// Check whether bot is at advantage. /// Check whether bot is at advantage.
/// </summary> /// </summary>
...@@ -901,7 +921,7 @@ namespace WindBot.Game.AI.Decks ...@@ -901,7 +921,7 @@ namespace WindBot.Game.AI.Decks
public override IList<ClientCard> OnSelectCard(IList<ClientCard> cards, int min, int max, int hint, bool cancelable) public override IList<ClientCard> OnSelectCard(IList<ClientCard> cards, int min, int max, int hint, bool cancelable)
{ {
ClientCard currentSolvingChain = Duel.GetCurrentSolvingChainCard(); ChainInfo currentSolvingChain = Duel.GetCurrentSolvingChainInfo();
if (currentSolvingChain != null) if (currentSolvingChain != null)
{ {
if (botSolvingCross) if (botSolvingCross)
...@@ -933,7 +953,7 @@ namespace WindBot.Game.AI.Decks ...@@ -933,7 +953,7 @@ namespace WindBot.Game.AI.Decks
} }
} }
if (currentSolvingChain.Controller == 1 && currentSolvingChain.IsCode(_CardId.EvenlyMatched)) if (currentSolvingChain.ActivatePlayer == 1 && currentSolvingChain.IsCode(_CardId.EvenlyMatched))
{ {
Logger.DebugWriteLine("=== Evenly Matched activated."); Logger.DebugWriteLine("=== Evenly Matched activated.");
List<ClientCard> banishList = new List<ClientCard>(); List<ClientCard> banishList = new List<ClientCard>();
...@@ -975,7 +995,7 @@ namespace WindBot.Game.AI.Decks ...@@ -975,7 +995,7 @@ namespace WindBot.Game.AI.Decks
return Util.CheckSelectCount(banishList, cards, min, max); return Util.CheckSelectCount(banishList, cards, min, max);
} }
if (currentSolvingChain.Controller == 0) if (currentSolvingChain.ActivatePlayer == 0)
{ {
if (hint == HintMsg.AddToHand) if (hint == HintMsg.AddToHand)
{ {
...@@ -1681,31 +1701,31 @@ namespace WindBot.Game.AI.Decks ...@@ -1681,31 +1701,31 @@ namespace WindBot.Game.AI.Decks
public override void OnChainSolved(int chainIndex) public override void OnChainSolved(int chainIndex)
{ {
botSolvingCross = false; botSolvingCross = false;
ClientCard currentCard = Duel.GetCurrentSolvingChainCard(); ChainInfo currentChain = Duel.GetCurrentSolvingChainInfo();
if (currentCard != null) if (currentChain != null && !Duel.IsCurrentSolvingChainNegated())
{ {
if (!Duel.IsCurrentSolvingChainNegated()) if (!Duel.IsCurrentSolvingChainNegated())
{ {
if (currentCard.IsCode(_CardId.LockBird)) if (currentChain.IsCode(_CardId.LockBird))
lockBirdSolved = true; lockBirdSolved = true;
if (currentCard.IsCode(_CardId.DimensionShifter)) if (currentChain.IsCode(_CardId.DimensionShifter))
dimensionShifterCount = 2; dimensionShifterCount = 2;
if (currentCard.Controller == 1) if (currentChain.ActivatePlayer == 1)
{ {
if (currentCard.IsCode(_CardId.MaxxC)) if (currentChain.IsCode(_CardId.MaxxC))
enemyActivateMaxxC = true; enemyActivateMaxxC = true;
if (currentCard.IsCode(_CardId.MulcharmyPurulia)) if (currentChain.IsCode(_CardId.MulcharmyPurulia))
enemyActivatePurulia = true; enemyActivatePurulia = true;
if (currentCard.IsCode(_CardId.MulcharmyFuwalos)) if (currentChain.IsCode(_CardId.MulcharmyFuwalos))
enemyActivateFuwalos = true; enemyActivateFuwalos = true;
if (currentCard.IsCode(_CardId.MulcharmyNyalus)) if (currentChain.IsCode(_CardId.MulcharmyNyalus))
enemyActivateNyalus = true; enemyActivateNyalus = true;
} }
if (currentCard.Controller == 0) if (currentChain.ActivatePlayer == 0)
{ {
foreach (int checkId in CheckBotSolvedList) foreach (int checkId in CheckBotSolvedList)
{ {
if (currentCard.IsCode(checkId)) if (currentChain.IsCode(checkId))
{ {
botSolvedCardIdList.Add(checkId); botSolvedCardIdList.Add(checkId);
} }
...@@ -2758,10 +2778,10 @@ namespace WindBot.Game.AI.Decks ...@@ -2758,10 +2778,10 @@ namespace WindBot.Game.AI.Decks
// whether to negate by cross // whether to negate by cross
if (ActivateDescription == Util.GetStringId(CardId.RyzealCross, 3)) if (ActivateDescription == Util.GetStringId(CardId.RyzealCross, 3))
{ {
ClientCard currentSolvingChain = Duel.GetCurrentSolvingChainCard(); ChainInfo currentChainInfo = Duel.GetCurrentSolvingChainInfo();
if (currentSolvingChain != null && !Duel.IsCurrentSolvingChainNegated()) if (currentChainInfo != null && !Duel.IsCurrentSolvingChainNegated())
{ {
if (CheckCardShouldNegate(currentSolvingChain)) if (CheckCardShouldNegate(currentChainInfo))
{ {
Logger.DebugWriteLine("** cross negate"); Logger.DebugWriteLine("** cross negate");
activatedCardIdList.Add(CardId.RyzealCross + 2); activatedCardIdList.Add(CardId.RyzealCross + 2);
...@@ -2780,6 +2800,11 @@ namespace WindBot.Game.AI.Decks ...@@ -2780,6 +2800,11 @@ namespace WindBot.Game.AI.Decks
Bot.Banished.Any(c => c != null && c.IsFaceup() && c.HasSetcode(SetcodeRyzeal) && (c.IsCanRevive() || !c.HasType(CardType.Xyz)))); Bot.Banished.Any(c => c != null && c.IsFaceup() && c.HasSetcode(SetcodeRyzeal) && (c.IsCanRevive() || !c.HasType(CardType.Xyz))));
flag |= Bot.MonsterZone.Count(c => c != null && c.IsFaceup() && c.HasType(CardType.Xyz) && c.HasSetcode(SetcodeRyzeal) && (c.Overlays.Count() > 0 || canSetMaterial)) > 0; flag |= Bot.MonsterZone.Count(c => c != null && c.IsFaceup() && c.HasType(CardType.Xyz) && c.HasSetcode(SetcodeRyzeal) && (c.Overlays.Count() > 0 || canSetMaterial)) > 0;
if (Duel.MainPhase.SpecialSummonableCards.Any(c => c.IsCode(CardId.RyzealDuodrive)))
{
flag |= RyzealDuodriveSpSummonCheck();
}
return flag; return flag;
} }
......
...@@ -695,8 +695,8 @@ namespace WindBot.Game.AI.Decks ...@@ -695,8 +695,8 @@ namespace WindBot.Game.AI.Decks
public override void OnChainSolved(int chainIndex) public override void OnChainSolved(int chainIndex)
{ {
ClientCard currentCard = Duel.GetCurrentSolvingChainCard(); ChainInfo currentCard = Duel.GetCurrentSolvingChainInfo();
if (currentCard != null && !Duel.IsCurrentSolvingChainNegated() && currentCard.Controller == 1) if (currentCard != null && !Duel.IsCurrentSolvingChainNegated() && currentCard.ActivatePlayer == 1)
{ {
if (currentCard.IsCode(_CardId.MaxxC)) if (currentCard.IsCode(_CardId.MaxxC))
enemyActivateMaxxC = true; enemyActivateMaxxC = true;
...@@ -706,7 +706,7 @@ namespace WindBot.Game.AI.Decks ...@@ -706,7 +706,7 @@ namespace WindBot.Game.AI.Decks
{ {
for (int i = 0; i < 5; ++i) for (int i = 0; i < 5; ++i)
{ {
if (Enemy.SpellZone[i] == currentCard) if (Enemy.SpellZone[i] == currentCard.RelatedCard)
{ {
infiniteImpermanenceList.Add(4 - i); infiniteImpermanenceList.Add(4 - i);
break; break;
......
...@@ -201,8 +201,8 @@ namespace WindBot.Game.AI.Decks ...@@ -201,8 +201,8 @@ namespace WindBot.Game.AI.Decks
public override void OnChainSolved(int chainIndex) public override void OnChainSolved(int chainIndex)
{ {
ClientCard currentCard = Duel.GetCurrentSolvingChainCard(); ChainInfo currentCard = Duel.GetCurrentSolvingChainInfo();
if (currentCard != null && currentCard.Controller == 1) if (currentCard != null && currentCard.ActivatePlayer == 1)
{ {
if (Duel.IsCurrentSolvingChainNegated()) if (Duel.IsCurrentSolvingChainNegated())
{ {
...@@ -212,16 +212,16 @@ namespace WindBot.Game.AI.Decks ...@@ -212,16 +212,16 @@ namespace WindBot.Game.AI.Decks
if (Bot.MonsterZone.GetFirstMatchingCard(c => c.HasRace(CardRace.SpellCaster) && c.IsFaceup()) != null if (Bot.MonsterZone.GetFirstMatchingCard(c => c.HasRace(CardRace.SpellCaster) && c.IsFaceup()) != null
&& Bot.HasInSpellZone(CardId.MagicianRightHand, true)) && Bot.HasInSpellZone(CardId.MagicianRightHand, true))
{ {
Logger.DebugWriteLine("MagicianRightHand negate: " + currentCard.Name ?? "???"); Logger.DebugWriteLine("MagicianRightHand negate: " + currentCard.RelatedCard.Name ?? "???");
MagicianRightHand_used = true; 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 if (Bot.MonsterZone.GetFirstMatchingCard(c => c.HasRace(CardRace.SpellCaster) && c.IsFaceup()) != null
&& Bot.HasInSpellZone(CardId.MagiciansLeftHand, true)) && Bot.HasInSpellZone(CardId.MagiciansLeftHand, true))
{ {
Logger.DebugWriteLine("MagiciansLeftHand negate: " + currentCard.Name ?? "???"); Logger.DebugWriteLine("MagiciansLeftHand negate: " + currentCard.RelatedCard.Name ?? "???");
MagiciansLeftHand_used = true; MagiciansLeftHand_used = true;
} }
} }
...@@ -236,7 +236,7 @@ namespace WindBot.Game.AI.Decks ...@@ -236,7 +236,7 @@ namespace WindBot.Game.AI.Decks
{ {
for (int i = 0; i < 5; ++i) for (int i = 0; i < 5; ++i)
{ {
if (Enemy.SpellZone[i] == currentCard) if (Enemy.SpellZone[i] == currentCard.RelatedCard)
{ {
Impermanence_list.Add(4 - i); Impermanence_list.Add(4 - i);
break; break;
......
...@@ -16,9 +16,6 @@ namespace WindBot.Game.AI ...@@ -16,9 +16,6 @@ namespace WindBot.Game.AI
public GameAI AI { get; private set; } public GameAI AI { get; private set; }
public AIUtil Util { 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 ExecutorType Type { get; private set; }
protected ClientCard Card { get; private set; } protected ClientCard Card { get; private set; }
protected int ActivateDescription { get; private set; } protected int ActivateDescription { get; private set; }
...@@ -247,16 +244,6 @@ namespace WindBot.Game.AI ...@@ -247,16 +244,6 @@ namespace WindBot.Game.AI
return; return;
} }
public void SetMain(MainPhase main)
{
Main = main;
}
public void SetBattle(BattlePhase battle)
{
Battle = battle;
}
/// <summary> /// <summary>
/// Set global variables Type, Card, ActivateDescription for Executor /// Set global variables Type, Card, ActivateDescription for Executor
/// </summary> /// </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);
}
}
}
...@@ -20,6 +20,7 @@ namespace WindBot.Game ...@@ -20,6 +20,7 @@ namespace WindBot.Game
public int LastChainPlayer { get; set; } public int LastChainPlayer { get; set; }
public CardLocation LastChainLocation { get; set; } public CardLocation LastChainLocation { get; set; }
public IList<ClientCard> CurrentChain { get; set; } public IList<ClientCard> CurrentChain { get; set; }
public IList<ChainInfo> CurrentChainInfo { get; set; }
public IList<ClientCard> ChainTargets { get; set; } public IList<ClientCard> ChainTargets { get; set; }
public IList<ClientCard> LastChainTargets { get; set; } public IList<ClientCard> LastChainTargets { get; set; }
public IList<ClientCard> ChainTargetOnly { get; set; } public IList<ClientCard> ChainTargetOnly { get; set; }
...@@ -37,6 +38,7 @@ namespace WindBot.Game ...@@ -37,6 +38,7 @@ namespace WindBot.Game
LastChainPlayer = -1; LastChainPlayer = -1;
LastChainLocation = 0; LastChainLocation = 0;
CurrentChain = new List<ClientCard>(); CurrentChain = new List<ClientCard>();
CurrentChainInfo = new List<ChainInfo>();
ChainTargets = new List<ClientCard>(); ChainTargets = new List<ClientCard>();
LastChainTargets = new List<ClientCard>(); LastChainTargets = new List<ClientCard>();
ChainTargetOnly = new List<ClientCard>(); ChainTargetOnly = new List<ClientCard>();
...@@ -45,6 +47,8 @@ namespace WindBot.Game ...@@ -45,6 +47,8 @@ namespace WindBot.Game
LastSummonedCards = new List<ClientCard>(); LastSummonedCards = new List<ClientCard>();
SolvingChainIndex = 0; SolvingChainIndex = 0;
NegatedChainIndexList = new List<int>(); NegatedChainIndexList = new List<int>();
MainPhase = new MainPhase();
BattlePhase = new BattlePhase();
} }
public ClientCard GetCard(int player, CardLocation loc, int seq) public ClientCard GetCard(int player, CardLocation loc, int seq)
...@@ -180,6 +184,12 @@ namespace WindBot.Game ...@@ -180,6 +184,12 @@ namespace WindBot.Game
return CurrentChain[SolvingChainIndex - 1]; return CurrentChain[SolvingChainIndex - 1];
} }
public ChainInfo GetCurrentSolvingChainInfo()
{
if (SolvingChainIndex == 0 || SolvingChainIndex > CurrentChainInfo.Count) return null;
return CurrentChainInfo[SolvingChainIndex - 1];
}
public bool IsCurrentSolvingChainNegated() public bool IsCurrentSolvingChainNegated()
{ {
return SolvingChainIndex > 0 && NegatedChainIndexList.Contains(SolvingChainIndex); return SolvingChainIndex > 0 && NegatedChainIndexList.Contains(SolvingChainIndex);
......
...@@ -193,7 +193,6 @@ namespace WindBot.Game ...@@ -193,7 +193,6 @@ namespace WindBot.Game
/// <returns>A new BattlePhaseAction containing the action to do.</returns> /// <returns>A new BattlePhaseAction containing the action to do.</returns>
public BattlePhaseAction OnSelectBattleCmd(BattlePhase battle) public BattlePhaseAction OnSelectBattleCmd(BattlePhase battle)
{ {
Executor.SetBattle(battle);
foreach (CardExecutor exec in Executor.Executors) foreach (CardExecutor exec in Executor.Executors)
{ {
if (exec.Type == ExecutorType.GoToMainPhase2 && battle.CanMainPhaseTwo && exec.Func()) // check if should enter main phase 2 directly if (exec.Type == ExecutorType.GoToMainPhase2 && battle.CanMainPhaseTwo && exec.Func()) // check if should enter main phase 2 directly
...@@ -352,7 +351,7 @@ namespace WindBot.Game ...@@ -352,7 +351,7 @@ namespace WindBot.Game
/// <param name="forced">You can't return -1 if this param is true.</param> /// <param name="forced">You can't return -1 if this param is true.</param>
/// <param name="timing">Current hint timing</param> /// <param name="timing">Current hint timing</param>
/// <returns>Index of the activated card or -1.</returns> /// <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); Executor.OnSelectChain(cards);
foreach (CardExecutor exec in Executor.Executors) foreach (CardExecutor exec in Executor.Executors)
...@@ -367,8 +366,17 @@ namespace WindBot.Game ...@@ -367,8 +366,17 @@ namespace WindBot.Game
} }
} }
} }
// If we're forced to chain, we chain the first card. However don't do anything. for (int i = 0; i < forces.Count; ++i)
return forced ? 0 : -1; {
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> /// <summary>
...@@ -440,7 +448,6 @@ namespace WindBot.Game ...@@ -440,7 +448,6 @@ namespace WindBot.Game
/// <returns>A new MainPhaseAction containing the action to do.</returns> /// <returns>A new MainPhaseAction containing the action to do.</returns>
public MainPhaseAction OnSelectIdleCmd(MainPhase main) public MainPhaseAction OnSelectIdleCmd(MainPhase main)
{ {
Executor.SetMain(main);
CheckSurrender(); CheckSurrender();
foreach (CardExecutor exec in Executor.Executors) foreach (CardExecutor exec in Executor.Executors)
{ {
......
...@@ -342,7 +342,7 @@ namespace WindBot.Game ...@@ -342,7 +342,7 @@ namespace WindBot.Game
if (player < 4) if (player < 4)
Logger.WriteLine(otherName + " say to " + myName + ": " + message); Logger.WriteLine(otherName + " say to " + myName + ": " + message);
else else
Logger.WriteLine("Server say to " + myName + ": " + message); Logger.WriteLine("System message(" + player + "): " + message);
} }
} }
...@@ -355,6 +355,7 @@ namespace WindBot.Game ...@@ -355,6 +355,7 @@ namespace WindBot.Game
packet.ReadByte(); packet.ReadByte();
packet.ReadByte(); packet.ReadByte();
int pcode = packet.ReadInt32(); int pcode = packet.ReadInt32();
Logger.DebugWriteLine("Error message received: " + msg + ", code: " + pcode);
if (msg == 2) //ERRMSG_DECKERROR if (msg == 2) //ERRMSG_DECKERROR
{ {
int code = pcode & 0xFFFFFFF; int code = pcode & 0xFFFFFFF;
...@@ -433,6 +434,7 @@ namespace WindBot.Game ...@@ -433,6 +434,7 @@ namespace WindBot.Game
// in case of ending duel in chain's solving // in case of ending duel in chain's solving
_duel.CurrentChain.Clear(); _duel.CurrentChain.Clear();
_duel.CurrentChainInfo.Clear();
_duel.ChainTargets.Clear(); _duel.ChainTargets.Clear();
_duel.ChainTargetOnly.Clear(); _duel.ChainTargetOnly.Clear();
_duel.SummoningCards.Clear(); _duel.SummoningCards.Clear();
...@@ -813,6 +815,8 @@ namespace WindBot.Game ...@@ -813,6 +815,8 @@ namespace WindBot.Game
if (card.Id == 0) if (card.Id == 0)
card.SetId(cardId); card.SetId(cardId);
int cc = GetLocalPlayer(packet.ReadByte()); int cc = GetLocalPlayer(packet.ReadByte());
packet.ReadInt16(); // trigger location + trigger sequence
int desc = packet.ReadInt32();
if (_debug) if (_debug)
if (card != null) Logger.WriteLine("(" + cc.ToString() + " 's " + (card.Name ?? "UnKnowCard") + " activate effect from " + (CardLocation)pcl + ")"); if (card != null) Logger.WriteLine("(" + cc.ToString() + " 's " + (card.Name ?? "UnKnowCard") + " activate effect from " + (CardLocation)pcl + ")");
_duel.LastChainLocation = (CardLocation)pcl; _duel.LastChainLocation = (CardLocation)pcl;
...@@ -821,6 +825,7 @@ namespace WindBot.Game ...@@ -821,6 +825,7 @@ namespace WindBot.Game
_duel.ChainTargetOnly.Clear(); _duel.ChainTargetOnly.Clear();
_duel.LastSummonPlayer = -1; _duel.LastSummonPlayer = -1;
_duel.CurrentChain.Add(card); _duel.CurrentChain.Add(card);
_duel.CurrentChainInfo.Add(new ChainInfo(card, cc, desc));
_duel.LastChainPlayer = cc; _duel.LastChainPlayer = cc;
} }
...@@ -855,6 +860,7 @@ namespace WindBot.Game ...@@ -855,6 +860,7 @@ namespace WindBot.Game
_duel.LastChainPlayer = -1; _duel.LastChainPlayer = -1;
_duel.LastChainLocation = 0; _duel.LastChainLocation = 0;
_duel.CurrentChain.Clear(); _duel.CurrentChain.Clear();
_duel.CurrentChainInfo.Clear();
_duel.ChainTargets.Clear(); _duel.ChainTargets.Clear();
_duel.LastChainTargets.Clear(); _duel.LastChainTargets.Clear();
_duel.ChainTargetOnly.Clear(); _duel.ChainTargetOnly.Clear();
...@@ -1213,16 +1219,19 @@ namespace WindBot.Game ...@@ -1213,16 +1219,19 @@ namespace WindBot.Game
packet.ReadByte(); // player packet.ReadByte(); // player
int count = packet.ReadByte(); int count = packet.ReadByte();
packet.ReadByte(); // specount packet.ReadByte(); // specount
bool forced = packet.ReadByte() != 0;
int hint1 = packet.ReadInt32(); // hint1 int hint1 = packet.ReadInt32(); // hint1
int hint2 = packet.ReadInt32(); // hint2 int hint2 = packet.ReadInt32(); // hint2
// TODO: use ChainInfo?
IList<ClientCard> cards = new List<ClientCard>(); IList<ClientCard> cards = new List<ClientCard>();
IList<int> descs = new List<int>(); IList<int> descs = new List<int>();
IList<bool> forces = new List<bool>();
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
{ {
packet.ReadByte(); // flag packet.ReadByte(); // flag
bool forced = packet.ReadByte() != 0;
int id = packet.ReadInt32(); int id = packet.ReadInt32();
int con = GetLocalPlayer(packet.ReadByte()); int con = GetLocalPlayer(packet.ReadByte());
int loc = packet.ReadByte(); int loc = packet.ReadByte();
...@@ -1241,6 +1250,7 @@ namespace WindBot.Game ...@@ -1241,6 +1250,7 @@ namespace WindBot.Game
cards.Add(card); cards.Add(card);
descs.Add(desc); descs.Add(desc);
forces.Add(forced);
} }
if (cards.Count == 0) if (cards.Count == 0)
...@@ -1249,13 +1259,13 @@ namespace WindBot.Game ...@@ -1249,13 +1259,13 @@ namespace WindBot.Game
return; return;
} }
if (cards.Count == 1 && forced) if (cards.Count == 1 && forces[0])
{ {
Connection.Send(CtosMessage.Response, 0); Connection.Send(CtosMessage.Response, 0);
return; 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) private void OnSelectCounter(BinaryReader packet)
...@@ -1639,6 +1649,11 @@ namespace WindBot.Game ...@@ -1639,6 +1649,11 @@ namespace WindBot.Game
int OpParam = packet.ReadInt32(); int OpParam = packet.ReadInt32();
int OpParam1 = OpParam & 0xffff; int OpParam1 = OpParam & 0xffff;
int OpParam2 = OpParam >> 16; int OpParam2 = OpParam >> 16;
if ((OpParam & 0x80000000) > 0)
{
OpParam1 = OpParam & 0x7fffffff;
OpParam2 = 0;
}
if (OpParam2 > 0 && OpParam1 > OpParam2) if (OpParam2 > 0 && OpParam1 > OpParam2)
{ {
card.OpParam1 = OpParam2; card.OpParam1 = OpParam2;
...@@ -2032,6 +2047,7 @@ namespace WindBot.Game ...@@ -2032,6 +2047,7 @@ namespace WindBot.Game
private void OnConfirmCards(BinaryReader packet) private void OnConfirmCards(BinaryReader packet)
{ {
/*int playerid = */packet.ReadByte(); /*int playerid = */packet.ReadByte();
/*int skip_panel = */packet.ReadByte();
int count = packet.ReadByte(); int count = packet.ReadByte();
for (int i = 0; i < count; ++ i) for (int i = 0; i < count; ++ i)
{ {
......
using System.IO; using System;
using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Text;
using YGOSharp.Network; using YGOSharp.Network;
using YGOSharp.Network.Enums; using YGOSharp.Network.Enums;
using YGOSharp.Network.Utils; using YGOSharp.Network.Utils;
...@@ -67,7 +67,12 @@ namespace WindBot.Game ...@@ -67,7 +67,12 @@ namespace WindBot.Game
private void OnConnected() 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); packet.WriteUnicode(Username, 20);
Connection.Send(packet); Connection.Send(packet);
...@@ -75,7 +80,7 @@ namespace WindBot.Game ...@@ -75,7 +80,7 @@ namespace WindBot.Game
packet = GamePacketFactory.Create(CtosMessage.JoinGame); packet = GamePacketFactory.Create(CtosMessage.JoinGame);
packet.Write(_proVersion); packet.Write(_proVersion);
packet.Write(junk); packet.Write(junk);
packet.WriteUnicode(_roomInfo, 30); packet.WriteUnicode(_roomInfo, 20);
Connection.Send(packet); Connection.Send(packet);
} }
...@@ -86,9 +91,8 @@ namespace WindBot.Game ...@@ -86,9 +91,8 @@ namespace WindBot.Game
public void Chat(string message) public void Chat(string message)
{ {
byte[] content = Encoding.Unicode.GetBytes(message + "\0");
BinaryWriter chat = GamePacketFactory.Create(CtosMessage.Chat); BinaryWriter chat = GamePacketFactory.Create(CtosMessage.Chat);
chat.Write(content); chat.WriteUnicodeAutoLength(message, 255);
Connection.Send(chat); Connection.Send(chat);
} }
......
...@@ -10,7 +10,7 @@ using System.Runtime.InteropServices; ...@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("IceYGO")] [assembly: AssemblyCompany("IceYGO")]
[assembly: AssemblyProduct("WindBot")] [assembly: AssemblyProduct("WindBot")]
[assembly: AssemblyCopyright("Copyright © IceYGO 2015-2017")] [assembly: AssemblyCopyright("Copyright © IceYGO 2015-2025")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
......
# WindBot # 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: ### How to use:
...@@ -139,10 +139,13 @@ WindBot can run as a "server", provide a http interface to create bot. ...@@ -139,10 +139,13 @@ WindBot can run as a "server", provide a http interface to create bot.
* Nekroz * Nekroz
### AI Template Generator ### Template Generator
A Java program which generate executor code from deck, made by Levyaton. A tool which generates a WindBot deck code template from a YGOPro deck file.
https://github.com/Levyaton/WindbotTemplateGenerator
You can use it to create a new deck for WindBot quickly.
https://mercury233.me/windbot/gen.html
### Server mode ### Server mode
...@@ -154,6 +157,11 @@ In this situation, it will be multi-threaded. This can be useful for servers, si ...@@ -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. 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 ### Known issues
* If one chain includes two activation that use `AI.SelectCard`, the second one won't select correctly. * If one chain includes two activation that use `AI.SelectCard`, the second one won't select correctly.
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>WindBot</RootNamespace> <RootNamespace>WindBot</RootNamespace>
<AssemblyName>WindBot</AssemblyName> <AssemblyName>WindBot</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
...@@ -30,9 +31,10 @@ ...@@ -30,9 +31,10 @@
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<StartupObject /> <StartupObject>WindBot.Program</StartupObject>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<ApplicationIcon>WindBot.ico</ApplicationIcon> <ApplicationIcon>WindBot.ico</ApplicationIcon>
...@@ -40,6 +42,12 @@ ...@@ -40,6 +42,12 @@
<PropertyGroup> <PropertyGroup>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Mono.Data.Sqlite"> <Reference Include="Mono.Data.Sqlite">
<HintPath>.\Mono.Data.Sqlite.dll</HintPath> <HintPath>.\Mono.Data.Sqlite.dll</HintPath>
...@@ -137,6 +145,7 @@ ...@@ -137,6 +145,7 @@
<Compile Include="Game\AI\ExecutorType.cs" /> <Compile Include="Game\AI\ExecutorType.cs" />
<Compile Include="Game\BattlePhase.cs" /> <Compile Include="Game\BattlePhase.cs" />
<Compile Include="Game\BattlePhaseAction.cs" /> <Compile Include="Game\BattlePhaseAction.cs" />
<Compile Include="Game\ChainInfo.cs" />
<Compile Include="Game\ClientCard.cs" /> <Compile Include="Game\ClientCard.cs" />
<Compile Include="Game\ClientField.cs" /> <Compile Include="Game\ClientField.cs" />
<Compile Include="Game\Deck.cs" /> <Compile Include="Game\Deck.cs" />
......
...@@ -26,7 +26,7 @@ namespace WindBot ...@@ -26,7 +26,7 @@ namespace WindBot
Host = "127.0.0.1"; Host = "127.0.0.1";
Port = 7911; Port = 7911;
HostInfo = ""; HostInfo = "";
Version = 0x1361; Version = 0x1362;
Hand = 0; Hand = 0;
Debug = false; Debug = false;
Chat = true; Chat = true;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
Surrender = 0x14, Surrender = 0x14,
TimeConfirm = 0x15, TimeConfirm = 0x15,
Chat = 0x16, Chat = 0x16,
ExternalAddress = 0x17,
HsToDuelist = 0x20, HsToDuelist = 0x20,
HsToObserver = 0x21, HsToObserver = 0x21,
HsReady = 0x22, HsReady = 0x22,
......
...@@ -6,15 +6,40 @@ namespace YGOSharp.Network.Utils ...@@ -6,15 +6,40 @@ namespace YGOSharp.Network.Utils
{ {
public static class BinaryExtensions public static class BinaryExtensions
{ {
// fixed length strings
public static void WriteUnicode(this BinaryWriter writer, string text, int len) public static void WriteUnicode(this BinaryWriter writer, string text, int len)
{ {
byte[] unicode = Encoding.Unicode.GetBytes(text); byte[] unicode = Encoding.Unicode.GetBytes(text);
byte[] result = new byte[len * 2]; byte[] result = new byte[len * 2];
int max = len * 2 - 2; int copy = unicode.Length;
Array.Copy(unicode, result, unicode.Length > max ? max : 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); 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) public static string ReadUnicode(this BinaryReader reader, int len)
{ {
byte[] unicode = reader.ReadBytes(len * 2); byte[] unicode = reader.ReadBytes(len * 2);
......
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