Commit ce478d35 authored by xiaoye's avatar xiaoye

Merge remote-tracking branch 'upstream/master' into 408

parents b2d7083a 1d25b276
...@@ -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
......
...@@ -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("")]
......
...@@ -129,6 +129,11 @@ Name=复制梁龙 Deck=Salamangreat Dialog=anothercopy.zh-CN ...@@ -129,6 +129,11 @@ Name=复制梁龙 Deck=Salamangreat Dialog=anothercopy.zh-CN
转生炎兽卡组。 转生炎兽卡组。
AI_LV3 SUPPORT_NEW_MASTER_RULE SUPPORT_MASTER_RULE_2020 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-凭依装着 !VI-1911-凭依装着
Name=VI-1911 Deck=FamiliarPossessed Dialog=VI-1911.zh-CN Name=VI-1911 Deck=FamiliarPossessed Dialog=VI-1911.zh-CN
凭依装着卡组。 凭依装着卡组。
......
#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
...@@ -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)
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -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;
......
...@@ -99,7 +99,13 @@ namespace WindBot.Game.AI ...@@ -99,7 +99,13 @@ namespace WindBot.Game.AI
public const int GhostOgreAndSnowRabbit = 59438930; public const int GhostOgreAndSnowRabbit = 59438930;
public const int GhostBelle = 73642296; public const int GhostBelle = 73642296;
public const int EffectVeiler = 97268402; public const int EffectVeiler = 97268402;
public const int GhostMournerMoonlitChill = 52038441;
public const int ArtifactLancea = 34267821; 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 CalledByTheGrave = 24224830;
public const int CrossoutDesignator = 65681983; public const int CrossoutDesignator = 65681983;
...@@ -120,9 +126,19 @@ namespace WindBot.Game.AI ...@@ -120,9 +126,19 @@ namespace WindBot.Game.AI
public const int ImperialOrder = 61740673; public const int ImperialOrder = 61740673;
public const int RoyalDecreel = 51452091; public const int RoyalDecreel = 51452091;
public const int NaturalExterio = 99916754;
public const int NaturiaBeast = 33198837; public const int NaturiaBeast = 33198837;
public const int SwordsmanLV7 = 37267041;
public const int AntiSpellFragrance = 58921041; 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_ShinraBansho = 49568943;
public const int VaylantzWorld_KonigWissen = 75952542; public const int VaylantzWorld_KonigWissen = 75952542;
public const int DivineArsenalAAZEUS_SkyThunder = 90448279; public const int DivineArsenalAAZEUS_SkyThunder = 90448279;
...@@ -214,6 +230,7 @@ namespace WindBot.Game.AI ...@@ -214,6 +230,7 @@ namespace WindBot.Game.AI
public const int FurHire = 0x114; public const int FurHire = 0x114;
public const int Altergeist = 0x103; public const int Altergeist = 0x103;
public const int Crusadia = 0x116; public const int Crusadia = 0x116;
public const int Danger = 0x11e;
public const int Endymion = 0x12a; public const int Endymion = 0x12a;
public const int AncientWarriors = 0x137; public const int AncientWarriors = 0x137;
public const int RescueACE = 0x18b; public const int RescueACE = 0x18b;
...@@ -780,7 +797,7 @@ namespace WindBot.Game.AI ...@@ -780,7 +797,7 @@ namespace WindBot.Game.AI
}; };
if (Util.GetLastChainCard().IsCode(ignoreList)) if (Util.GetLastChainCard().IsCode(ignoreList))
return false; 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 false;
return Duel.LastChainPlayer == 1; return Duel.LastChainPlayer == 1;
} }
...@@ -1599,6 +1616,12 @@ namespace WindBot.Game.AI ...@@ -1599,6 +1616,12 @@ namespace WindBot.Game.AI
|| (calledbytheGraveIdCountMap.ContainsKey(cardId) && calledbytheGraveIdCountMap[cardId] > 0); || (calledbytheGraveIdCountMap.ContainsKey(cardId) && calledbytheGraveIdCountMap[cardId] > 0);
} }
protected int GetCalledbytheGraveIdCount(int cardId)
{
if (!calledbytheGraveIdCountMap.ContainsKey(cardId)) return 0;
return calledbytheGraveIdCountMap[cardId];
}
protected virtual bool DefaultSetForDiabellze() protected virtual bool DefaultSetForDiabellze()
{ {
......
...@@ -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; }
...@@ -237,14 +234,14 @@ namespace WindBot.Game.AI ...@@ -237,14 +234,14 @@ namespace WindBot.Game.AI
return 0; return 0;
} }
public void SetMain(MainPhase main) /// <summary>
{ /// Called when card is successfully special summoned.
Main = main; /// Used on monsters that can only special summoned once per turn.
} /// </summary>
public virtual void OnSpSummoned()
public void SetBattle(BattlePhase battle)
{ {
Battle = battle; // For overriding
return;
} }
/// <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);
}
}
}
...@@ -350,6 +350,11 @@ namespace WindBot.Game ...@@ -350,6 +350,11 @@ namespace WindBot.Game
return Id == id || Alias - Id < 20 && Alias == id; 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() public bool HasXyzMaterial()
{ {
return Overlays.Count > 0; return Overlays.Count > 0;
......
...@@ -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)
{ {
......
...@@ -298,6 +298,8 @@ namespace WindBot.Game ...@@ -298,6 +298,8 @@ namespace WindBot.Game
string otherName = (player == 0) ? _room.Names[1] : _room.Names[0]; string otherName = (player == 0) ? _room.Names[1] : _room.Names[0];
if (player < 4) if (player < 4)
Logger.DebugWriteLine(otherName + " say to " + myName + ": " + message); Logger.DebugWriteLine(otherName + " say to " + myName + ": " + message);
else
Logger.DebugWriteLine("System message(" + player + "): " + message);
} }
private void OnErrorMsg(BinaryReader packet) private void OnErrorMsg(BinaryReader packet)
...@@ -308,6 +310,7 @@ namespace WindBot.Game ...@@ -308,6 +310,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;
...@@ -386,6 +389,7 @@ namespace WindBot.Game ...@@ -386,6 +389,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();
...@@ -764,6 +768,8 @@ namespace WindBot.Game ...@@ -764,6 +768,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;
...@@ -772,6 +778,7 @@ namespace WindBot.Game ...@@ -772,6 +778,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;
} }
...@@ -806,6 +813,7 @@ namespace WindBot.Game ...@@ -806,6 +813,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();
...@@ -1017,7 +1025,13 @@ namespace WindBot.Game ...@@ -1017,7 +1025,13 @@ namespace WindBot.Game
packet.ReadByte(); // pos packet.ReadByte(); // pos
ClientCard card; ClientCard card;
if (((int)loc & (int)CardLocation.Overlay) != 0) if (((int)loc & (int)CardLocation.Overlay) != 0)
{
card = new ClientCard(id, CardLocation.Overlay, -1); 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 else
{ {
card = _duel.GetCard(player, loc, seq); card = _duel.GetCard(player, loc, seq);
...@@ -1158,16 +1172,19 @@ namespace WindBot.Game ...@@ -1158,16 +1172,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();
...@@ -1186,6 +1203,7 @@ namespace WindBot.Game ...@@ -1186,6 +1203,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)
...@@ -1194,13 +1212,13 @@ namespace WindBot.Game ...@@ -1194,13 +1212,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)
...@@ -1584,6 +1602,11 @@ namespace WindBot.Game ...@@ -1584,6 +1602,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;
...@@ -1977,6 +2000,7 @@ namespace WindBot.Game ...@@ -1977,6 +2000,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;
...@@ -65,7 +65,12 @@ namespace WindBot.Game ...@@ -65,7 +65,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);
...@@ -73,7 +78,7 @@ namespace WindBot.Game ...@@ -73,7 +78,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);
} }
...@@ -84,9 +89,8 @@ namespace WindBot.Game ...@@ -84,9 +89,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:
...@@ -136,10 +136,13 @@ WindBot can run as a "server", provide a http interface to create bot. ...@@ -136,10 +136,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
...@@ -151,6 +154,11 @@ In this situation, it will be multi-threaded. This can be useful for servers, si ...@@ -151,6 +154,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.
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<StartupObject /> <StartupObject>WindBot.Program</StartupObject>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<ApplicationIcon>WindBot.ico</ApplicationIcon> <ApplicationIcon>WindBot.ico</ApplicationIcon>
...@@ -42,6 +42,12 @@ ...@@ -42,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>
...@@ -62,6 +68,7 @@ ...@@ -62,6 +68,7 @@
<Compile Include="Game\AI\CardSelector.cs" /> <Compile Include="Game\AI\CardSelector.cs" />
<Compile Include="Game\AI\DeckAttribute.cs" /> <Compile Include="Game\AI\DeckAttribute.cs" />
<Compile Include="Game\AI\DecksManager.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\AlbazExecutor.cs" />
<Compile Include="Game\AI\Decks\AltergeistExecutor.cs" /> <Compile Include="Game\AI\Decks\AltergeistExecutor.cs" />
<Compile Include="Game\AI\Decks\BraveExecutor.cs" /> <Compile Include="Game\AI\Decks\BraveExecutor.cs" />
...@@ -138,6 +145,7 @@ ...@@ -138,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" />
......
...@@ -24,7 +24,7 @@ namespace WindBot ...@@ -24,7 +24,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