Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*.user
*.sln.docstates
.vs/
.vscode/

# Build results

Expand Down
5 changes: 5 additions & 0 deletions BotWrapper/bot.conf
Original file line number Diff line number Diff line change
Expand Up @@ -272,4 +272,9 @@ AI_LV4 SUPPORT_MASTER_RULE_2020
!今晚有宵夜吗-码丽丝
Name=今晚有宵夜吗 Deck=MalissOCG Dialog=Xiaoye.zh-CN
码丽丝卡组。
AI_LV4 SUPPORT_MASTER_RULE_2020

!尼亚-王家的神殿
Name=尼亚 Deck=Apophis Dialog=near.zh-CN
王家的神殿卡组。
AI_LV4 SUPPORT_MASTER_RULE_2020
59 changes: 59 additions & 0 deletions Decks/AI_Apophis.ydk
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#created by ...
#main
62514770
60411677
60411677
63198739
63198739
97522863
97522863
97522863
49238328
49238328
73628505
29095457
56506740
56506740
56506740
69299029
69299029
69299029
6325660
6325660
6325660
10045474
10045474
10045474
40366667
40366667
58053438
58053438
58053438
97045737
97045737
97045737
85888377
85888377
95561146
95561146
95561146
59576447
78114463
78114463
#extra
97800311
97800311
97800311
96633955
96633955
84815190
84815190
26096328
38354018
46772449
29301450
1528054
1528054
98978921
98978921
!side
3,076 changes: 3,076 additions & 0 deletions Game/AI/Decks/ApophisExecutor.cs

Large diffs are not rendered by default.

175 changes: 173 additions & 2 deletions Game/AI/DefaultExecutor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using YGOSharp.OCGWrapper.Enums;
Expand Down Expand Up @@ -143,6 +143,12 @@ protected class _CardId
public const int VaylantzWorld_KonigWissen = 75952542;
public const int DivineArsenalAAZEUS_SkyThunder = 90448279;
public const int LightningStorm = 14532163;
public const int MistakenArrest = 4227096;
public const int ThunderKingRaiOh = 71564252;
public const int ThunderDragonColossus = 15291624;
public const int DeckLockdown = 1149109;
public const int DoomZDestruction = 80320877;
public const int Mistake = 59305593;

public const int BelialMarquisOfDarkness = 33655493;
public const int ChirubiméPrincessOfAutumnLeaves = 87294988;
Expand Down Expand Up @@ -224,6 +230,8 @@ protected class _Setcode
public const int EarthboundImmortal = 0x1021;
public const int Naturia = 0x2a;
public const int Nordic = 0x42;
public const int TimeLord = 0x4a;

public const int Harpie = 0x64;
public const int Madolche = 0x71;
public const int Ghostrick = 0x8d;
Expand Down Expand Up @@ -255,6 +263,18 @@ protected DefaultExecutor(GameAI ai, Duel duel)
protected int lightningStormOption = -1;
Dictionary<int, int> calledbytheGraveIdCountMap = new Dictionary<int, int>();
List<int> crossoutDesignatorIdList = new List<int>();
int mistakenArrestAffectedCount = 0;
/// <summary>
/// List of effect IDs that have been resolved this turn.
/// </summary>
protected List<int> resolvedEffectIdList = new List<int>();
/// <summary>
/// List of effect IDs that have been resolved by enemy this turn.
/// </summary>
protected List<int> enemyResolvedEffectIdList = new List<int>();

/// <summary>Columns 0-4 on Bot's field negated by Infinite Impermanence (enemy's col converted to ours: 4-col). Cleared at turn start.</summary>
protected List<int> infiniteImpermanenceNegatedColumns = new List<int>();

/// <summary>
/// Defined:
Expand Down Expand Up @@ -578,6 +598,42 @@ public override IList<ClientCard> OnSelectCard(IList<ClientCard> cards, int min,
return null;
}

public override void OnPlayerHint(int player, int hintType, int description)
{
base.OnPlayerHint(player, hintType, description);
if (player != 0 && player != 1)
return;
ClientField field = (player == 0) ? Bot : Enemy;
if (hintType == (int)PlayerHintType.DescAdd)
field.HintDescriptions.Add(description);
else if (hintType == (int)PlayerHintType.DescRemove)
field.HintDescriptions.Remove(description);
}

public override void OnHintZone(int player, int zone)
{
base.OnHintZone(player, zone);
ChainInfo currentChainInfo = Duel.GetCurrentSolvingChainInfo();
if (currentChainInfo != null) {
if (currentChainInfo.IsCode(_CardId.InfiniteImpermanence)) {
// Zone bit mapping: 0x100=col0, 0x200=col1, 0x400=col2, 0x800=col3, 0x1000=col4.
for (int i = 0; i <= 4; i++)
{
if ((zone & (0x100 << i)) == 0)
continue;
if (currentChainInfo.ActivatePlayer == 0)
{
infiniteImpermanenceNegatedColumns.Add(i);
}
else
{
infiniteImpermanenceNegatedColumns.Add(4 - i);
}
}
}
}
}

public override void OnReceivingAnnouce(int player, int data)
{
if (player == 1 && data == Util.GetStringId(_CardId.LightningStorm, 0) || data == Util.GetStringId(_CardId.LightningStorm, 1))
Expand All @@ -588,6 +644,39 @@ public override void OnReceivingAnnouce(int player, int data)
base.OnReceivingAnnouce(player, data);
}

public override void OnChainSolved(int chainIndex)
{
ChainInfo currentChain = Duel.GetCurrentSolvingChainInfo();
if (currentChain != null && !Duel.IsCurrentSolvingChainNegated())
{
if (currentChain.IsActivateCode(_CardId.LockBird))
{
resolvedEffectIdList.Add(_CardId.LockBird);
}
if (currentChain.ActivatePlayer == 1)
{
if (currentChain.IsActivateCode(_CardId.MaxxC))
enemyResolvedEffectIdList.Add(_CardId.MaxxC);
if (currentChain.IsActivateCode(_CardId.MulcharmyPurulia))
enemyResolvedEffectIdList.Add(_CardId.MulcharmyPurulia);
if (currentChain.IsActivateCode(_CardId.MulcharmyFuwalos))
enemyResolvedEffectIdList.Add(_CardId.MulcharmyFuwalos);
if (currentChain.IsActivateCode(_CardId.MulcharmyNyalus))
enemyResolvedEffectIdList.Add(_CardId.MulcharmyNyalus);
if (currentChain.IsActivateCode(_CardId.MistakenArrest))
{
if (Duel.Player == 1)
{
mistakenArrestAffectedCount = Math.Max(mistakenArrestAffectedCount, 3);
} else
{
mistakenArrestAffectedCount = Math.Max(mistakenArrestAffectedCount, 2);
}
}
}
}
}

public override void OnChainEnd()
{
lightningStormOption = -1;
Expand All @@ -599,7 +688,15 @@ public override void OnChainEnd()
/// </summary>
public override void OnNewTurn()
{
if (Duel.Turn <= 1) calledbytheGraveIdCountMap.Clear();
infiniteImpermanenceNegatedColumns.Clear();
resolvedEffectIdList.Clear();
enemyResolvedEffectIdList.Clear();
if (Duel.Turn <= 1)
{
calledbytheGraveIdCountMap.Clear();
mistakenArrestAffectedCount = 0;
}
mistakenArrestAffectedCount = Math.Max(mistakenArrestAffectedCount - 1, 0);
List<int> keyList = calledbytheGraveIdCountMap.Keys.ToList();
foreach (int dic in keyList)
{
Expand Down Expand Up @@ -1653,5 +1750,79 @@ protected virtual bool DefaultSetForDiabellze()
}
return false;
}

/// <summary>
/// Check whether all available spell columns are negated.
/// </summary>
/// <returns></returns>
protected bool DefaultCheckAllAvailableSpellColumnNegated()
{
for (int i = 0; i < 5; i++) {
// occupied
if (Bot.SpellZone[i] != null) {
continue;
}
// negated
if (infiniteImpermanenceNegatedColumns.Contains(i)) {
continue;
}
// have empty column that's not negated
return false;
}
// all columns are negated
return true;
}

/// <summary>
/// Check whether the spells will be negated.
/// </summary>
/// <param name="card"></param>
/// <returns></returns>
protected bool DefaultCheckWhetherSpellActivateWillBeNegated(ClientCard card)
{
if (card == null) return false;
if (card.Location == CardLocation.SpellZone)
{
return infiniteImpermanenceNegatedColumns.Contains(card.Sequence);
}
// check whether will be negated by Infinite Impermanence
return DefaultCheckAllAvailableSpellColumnNegated();
}

/// <summary>
/// Check whether bot can search cards from deck.
/// </summary>
/// <returns></returns>
protected bool DefaultCheckWhetherBotCanSearch()
{
if (resolvedEffectIdList.Contains(_CardId.LockBird))
return false;
if (mistakenArrestAffectedCount > 0)
return false;
if (Bot.HasInMonstersZone(_CardId.ThunderKingRaiOh, notDisabled: true, faceUp: true)
|| Enemy.HasInMonstersZone(_CardId.ThunderKingRaiOh, notDisabled: true, faceUp: true))
return false;
if (Enemy.HasInMonstersZone(_CardId.ThunderDragonColossus))
return false;
if (Bot.HasInSpellZone(_CardId.DeckLockdown, notDisabled: true, faceUp: true)
|| Enemy.HasInSpellZone(_CardId.DeckLockdown, notDisabled: true, faceUp: true)
|| Bot.HasInSpellZone(_CardId.Mistake, notDisabled: true, faceUp: true)
|| Enemy.HasInSpellZone(_CardId.Mistake, notDisabled: true, faceUp: true))
return false;
if (Enemy.HasInSpellZone(_CardId.DoomZDestruction, notDisabled: true, faceUp: true))
return false;
return true;
}

/// <summary>
/// Check whether enemy can draw cards.
/// </summary>
/// <returns></returns>
protected bool DefaultCheckWhetherEnemyCanDraw()
{
if (resolvedEffectIdList.Contains(_CardId.LockBird))
return false;
return true;
}
}
}
23 changes: 22 additions & 1 deletion Game/AI/Executor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using YGOSharp.OCGWrapper.Enums;
Expand Down Expand Up @@ -121,6 +121,27 @@ public virtual void OnDraw(int player)
// Some AI need do something on draw
}

/// <summary>
/// Called when a PlayerHint is received (e.g. effect description add/remove; can be used to track "once per turn" usage).
/// </summary>
/// <param name="player">Player index</param>
/// <param name="hintType">Hint type, see PlayerHintType (DescAdd=6, DescRemove=7)</param>
/// <param name="description">Effect description id (peffect->description)</param>
public virtual void OnPlayerHint(int player, int hintType, int description)
{
// For overriding
}

/// <summary>
/// Called when a zone hint is received.
/// </summary>
/// <param name="player">Player index.</param>
/// <param name="zone">Zone data (hinted zones, bit field).</param>
public virtual void OnHintZone(int player, int zone)
{
// For overriding
}

public virtual void OnMove(ClientCard card, int previousControler, int previousLocation, int currentControler, int currentLocation)
{
// Some AI need do something on card's moving
Expand Down
7 changes: 7 additions & 0 deletions Game/ChainInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class ChainInfo
public ClientCard RelatedCard { get; private set; }
public int ActivatePlayer { get; private set; }
public int ActivateId { get; private set; }
public int ActivateAlias { get; private set; }
public int ActivateController { get; private set; }
public int ActivatePosition { get; private set; }
public int ActivateSequence { get; private set; }
Expand All @@ -35,6 +36,7 @@ public ChainInfo(ClientCard card, int player, int desc)
RelatedCard = card;
ActivatePlayer = player;
ActivateId = card.Id;
ActivateAlias = card.Alias;
ActivateController = card.Controller;
ActivatePosition = card.Position;
ActivateSequence = card.Sequence;
Expand All @@ -61,6 +63,11 @@ public bool HasLocation(CardLocation location)
return ((int)ActivateLocation & (int)location) != 0;
}

public bool IsActivateCode(int id)
{
return ActivateId == id || Math.Abs(ActivateAlias - ActivateId) <= 20 && ActivateAlias == id;
}

public bool IsCode(int id)
{
return RelatedCard != null && RelatedCard.IsCode(id);
Expand Down
3 changes: 3 additions & 0 deletions Game/ClientField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public class ClientField
public ClientCard BattlingMonster;
public bool UnderAttack;

public HashSet<int> HintDescriptions { get; private set; }

public ClientField()
{
}
Expand All @@ -32,6 +34,7 @@ public void Init(int deck, int extra)
Banished = new List<ClientCard>();
Deck = new List<ClientCard>();
ExtraDeck = new List<ClientCard>();
HintDescriptions = new HashSet<int>();

for (int i = 0; i < deck; ++i)
Deck.Add(new ClientCard(0, CardLocation.Deck, -1));
Expand Down
Loading