Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
W
windbot
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
windbot
Commits
078ad579
Commit
078ad579
authored
Sep 18, 2024
by
Tang Xinwei
1
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "发牌姬第二期AI智力修复:盖谜题、时间魔术师、链接召唤过滤、宝箱怪逻辑"
This reverts commit
7e8bc837
.
parent
7e8bc837
Pipeline
#29863
passed with stages
in 1 minute and 50 seconds
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
679 additions
and
828 deletions
+679
-828
Game/AI/DefaultExecutor.cs
Game/AI/DefaultExecutor.cs
+665
-811
Game/GameAI.cs
Game/GameAI.cs
+14
-17
No files found.
Game/AI/DefaultExecutor.cs
View file @
078ad579
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Linq
;
using
YGOSharp.OCGWrapper.Enums
;
using
YGOSharp.OCGWrapper.Enums
;
...
@@ -229,75 +229,8 @@ namespace WindBot.Game.AI
...
@@ -229,75 +229,8 @@ namespace WindBot.Game.AI
AddExecutor
(
ExecutorType
.
Activate
,
_CardId
.
VaylantzWorld_KonigWissen
,
DefaultVaylantzWorld_KonigWissen
);
AddExecutor
(
ExecutorType
.
Activate
,
_CardId
.
VaylantzWorld_KonigWissen
,
DefaultVaylantzWorld_KonigWissen
);
AddExecutor
(
ExecutorType
.
Activate
,
_CardId
.
SantaClaws
);
AddExecutor
(
ExecutorType
.
Activate
,
_CardId
.
SantaClaws
);
AddExecutor
(
ExecutorType
.
SpellSet
,
DefaultSetForDiabellze
);
AddExecutor
(
ExecutorType
.
SpellSet
,
DefaultSetForDiabellze
);
DealerMaidenModeAddCardExecutor
();
//发牌姬行为放到单独函数统一管理
}
void
DealerMaidenModeAddCardExecutor
()
{
SetFuncFilter
(
ExecutorType
.
Repos
,
()
=>
{
if
(
Card
.
IsCode
(
1102515
))
return
false
;
return
true
;
});
SetFuncFilter
(
ExecutorType
.
Activate
,
()
=>
{
if
(
Card
.
IsCode
(
5990062
))
return
Bot
.
HasInSpellZone
(
9373534
);
//[大逆转谜题]只有在自己场上有手里剑覆盖的场合才发动
if
(
Card
.
IsCode
(
3493058
))
return
Enemy
.
GetSpellCount
()
>
0
;
//[骰子旋风]对方玩家场上有魔陷才发动
if
(
Card
.
IsCode
(
22802010
))
//[无差别崩坏]自己场上怪兽少于对方才发动
return
Bot
.
MonsterZone
.
Count
(
c
=>
c
!=
null
&&
c
.
IsFaceup
()
&&
!
c
.
HasType
(
CardType
.
Link
))
<
Enemy
.
MonsterZone
.
Count
(
c
=>
c
!=
null
&&
c
.
IsFaceup
()
&&
!
c
.
HasType
(
CardType
.
Link
));
return
false
;
});
SetFuncFilter
(
ExecutorType
.
SummonOrSet
,
()
=>
{
if
(
Card
.
IsCode
(
71625222
))
return
Enemy
.
GetMonsterCount
()
>
0
;
//[时间魔术师]对方场上有怪兽存在才召唤
int
[]
codes
=
new
[]
{
23434538
,
46502744
,
87170768
,
25137581
,
14558127
,
60643553
,
27204311
,
94145021
,
59438930
,
2830693
,
19665973
,
18964575
,
34267821
,
24508238
,
78661338
,
84192580
,
52038441
,
62015408
};
if
(
Card
.
IsCode
(
codes
))
return
false
;
//过滤手坑
return
true
;
});
SetFuncFilter
(
ExecutorType
.
SpSummon
,()
=>
{
if
(
Card
.
HasType
(
CardType
.
Link
))
//链接怪兽特殊召唤前过滤
{
List
<
ClientCard
>
cards
=
Bot
.
GetMonsters
();
List
<
ClientCard
>
noLinkCards
=
Bot
.
GetMonsters
().
Where
(
card
=>
card
==
null
||
card
.
IsFacedown
()
||
card
.
Level
>=
8
||
card
.
LinkCount
>=
4
||
card
.
Rank
>=
8
||
card
.
Attack
>=
3000
).
ToList
();
foreach
(
var
card
in
noLinkCards
)
cards
.
Remove
(
card
);
int
link_count
=
0
;
foreach
(
var
card
in
cards
)
{
link_count
+=
(
card
.
HasType
(
CardType
.
Link
))
?
card
.
LinkCount
:
1
;
if
(
link_count
>=
Card
.
LinkCount
)
return
true
;
}
}
return
false
;
});
AddExecutor
(
ExecutorType
.
Activate
,
DefaultGambleCard
);
//默认发动的赌博卡
AddExecutor
(
ExecutorType
.
SpellSet
,
9373534
);
//[封魔手里剑]始终盖放
}
BattlePhaseAction
DealerMaidenModeOnSelectAttackTarget
(
ClientCard
attacker
,
IList
<
ClientCard
>
defenders
)
{
if
(
attacker
.
IsCode
(
1102515
))
//暗黑之宝箱怪 LV3
{
List
<
ClientCard
>
attakposCards
=
defenders
.
Where
(
card
=>
card
!=
null
&&
card
.
IsAttack
()).
ToList
();
attakposCards
.
Sort
(
CardContainer
.
CompareCardAttack
);
if
(
attakposCards
.
Count
()
<=
0
)
return
null
;
foreach
(
ClientCard
defender
in
attakposCards
)
{
attacker
.
RealPower
=
attacker
.
Attack
;
defender
.
RealPower
=
defender
.
Attack
;
if
(!
OnPreBattleBetween
(
attacker
,
defender
))
continue
;
if
((
defender
.
RealPower
-
attacker
.
RealPower
>
Bot
.
LifePoints
)
||
attacker
.
RealPower
>
defender
.
RealPower
)
continue
;
return
AI
.
Attack
(
attacker
,
defender
);
}
}
return
null
;
}
}
protected
int
lightningStormOption
=
-
1
;
protected
int
lightningStormOption
=
-
1
;
Dictionary
<
int
,
int
>
calledbytheGraveIdCountMap
=
new
Dictionary
<
int
,
int
>();
Dictionary
<
int
,
int
>
calledbytheGraveIdCountMap
=
new
Dictionary
<
int
,
int
>();
List
<
int
>
crossoutDesignatorIdList
=
new
List
<
int
>();
List
<
int
>
crossoutDesignatorIdList
=
new
List
<
int
>();
...
@@ -382,13 +315,11 @@ namespace WindBot.Game.AI
...
@@ -382,13 +315,11 @@ namespace WindBot.Game.AI
/// <returns>BattlePhaseAction including the target, or null (in this situation, GameAI will check the next attacker)</returns>
/// <returns>BattlePhaseAction including the target, or null (in this situation, GameAI will check the next attacker)</returns>
public
override
BattlePhaseAction
OnSelectAttackTarget
(
ClientCard
attacker
,
IList
<
ClientCard
>
defenders
)
public
override
BattlePhaseAction
OnSelectAttackTarget
(
ClientCard
attacker
,
IList
<
ClientCard
>
defenders
)
{
{
var
action
=
DealerMaidenModeOnSelectAttackTarget
(
attacker
,
defenders
);
foreach
(
ClientCard
defender
in
defenders
)
if
(
action
!=
null
)
return
action
;
foreach
(
ClientCard
defender
in
defenders
)
{
{
attacker
.
RealPower
=
attacker
.
Attack
;
attacker
.
RealPower
=
attacker
.
Attack
;
defender
.
RealPower
=
defender
.
GetDefensePower
();
defender
.
RealPower
=
defender
.
GetDefensePower
();
if
(!
OnPreBattleBetween
(
attacker
,
defender
))
//对这个逻辑进行修改
if
(!
OnPreBattleBetween
(
attacker
,
defender
))
continue
;
continue
;
if
(
attacker
.
RealPower
>
defender
.
RealPower
||
(
attacker
.
RealPower
>=
defender
.
RealPower
&&
attacker
.
IsLastAttacker
&&
defender
.
IsAttack
()))
if
(
attacker
.
RealPower
>
defender
.
RealPower
||
(
attacker
.
RealPower
>=
defender
.
RealPower
&&
attacker
.
IsLastAttacker
&&
defender
.
IsAttack
()))
...
@@ -581,10 +512,10 @@ namespace WindBot.Game.AI
...
@@ -581,10 +512,10 @@ namespace WindBot.Game.AI
return
false
;
return
false
;
}
}
/// <summary>
/// <summary>
/// Set when this card can't beat the enemies
/// Set when this card can't beat the enemies
/// </summary>
/// </summary>
public
override
bool
OnSelectMonsterSummonOrSet
(
ClientCard
card
)
public
override
bool
OnSelectMonsterSummonOrSet
(
ClientCard
card
)
{
{
return
card
.
Level
<=
4
&&
Bot
.
GetMonsters
().
Count
(
m
=>
m
.
IsFaceup
())
==
0
&&
Util
.
IsAllEnemyBetterThanValue
(
card
.
Attack
,
true
);
return
card
.
Level
<=
4
&&
Bot
.
GetMonsters
().
Count
(
m
=>
m
.
IsFaceup
())
==
0
&&
Util
.
IsAllEnemyBetterThanValue
(
card
.
Attack
,
true
);
}
}
...
@@ -616,740 +547,672 @@ namespace WindBot.Game.AI
...
@@ -616,740 +547,672 @@ namespace WindBot.Game.AI
extraDeck
[
shuffleCount
]
=
extraDeck
[
index
];
extraDeck
[
shuffleCount
]
=
extraDeck
[
index
];
extraDeck
[
index
]
=
tempCard
;
extraDeck
[
index
]
=
tempCard
;
}
}
return
Util
.
CheckSelectCount
(
extraDeck
,
cards
,
min
,
max
);
return
Util
.
CheckSelectCount
(
extraDeck
,
cards
,
min
,
max
);
}
}
if
(
hint
==
HintMsg
.
LinkMaterial
)
return
null
;
}
public
override
void
OnReceivingAnnouce
(
int
player
,
int
data
)
{
if
(
player
==
1
&&
data
==
Util
.
GetStringId
(
_CardId
.
LightningStorm
,
0
)
||
data
==
Util
.
GetStringId
(
_CardId
.
LightningStorm
,
1
))
{
lightningStormOption
=
data
-
Util
.
GetStringId
(
_CardId
.
LightningStorm
,
0
);
}
base
.
OnReceivingAnnouce
(
player
,
data
);
}
public
override
void
OnChainEnd
()
{
lightningStormOption
=
-
1
;
base
.
OnChainEnd
();
}
/// <summary>
/// Reset variables for new turn.
/// </summary>
public
override
void
OnNewTurn
()
{
if
(
Duel
.
Turn
<=
1
)
calledbytheGraveIdCountMap
.
Clear
();
List
<
int
>
keyList
=
calledbytheGraveIdCountMap
.
Keys
.
ToList
();
foreach
(
int
dic
in
keyList
)
{
{
if
(
AI
.
HaveSelectedCards
())
return
null
;
if
(
calledbytheGraveIdCountMap
[
dic
]
>
0
)
List
<
ClientCard
>
result
=
new
List
<
ClientCard
>(
cards
);
List
<
ClientCard
>
powerfulMonsters
=
new
List
<
ClientCard
>();
List
<
ClientCard
>
lowMonsters
=
new
List
<
ClientCard
>();
foreach
(
ClientCard
card
in
result
)
{
{
if
(
card
.
Level
>=
8
||
card
.
LinkCount
>=
4
||
calledbytheGraveIdCountMap
[
dic
]
-=
1
;
card
.
Rank
>=
8
||
card
.
Attack
>=
3000
)
powerfulMonsters
.
Add
(
card
);
}
else
lowMonsters
.
Add
(
card
);
}
}
crossoutDesignatorIdList
.
Clear
();
lowMonsters
.
Sort
(
CardContainer
.
CompareCardAttack
);
powerfulMonsters
.
Sort
(
CardContainer
.
CompareCardAttack
);
base
.
OnNewTurn
(
);
powerfulMonsters
.
Reverse
();
}
lowMonsters
.
AddRange
(
powerfulMonsters
);
return
Util
.
CheckSelectCount
(
lowMonsters
,
cards
,
min
,
max
);
public
override
void
OnMove
(
ClientCard
card
,
int
previousControler
,
int
previousLocation
,
int
currentControler
,
int
currentLocation
)
}
{
if
(
hint
==
HintMsg
.
Destroy
)
if
(
card
!=
null
)
{
{
if
(
AI
.
HaveSelectedCards
())
return
null
;
ClientCard
currentSolvingChain
=
Duel
.
GetCurrentSolvingChainCard
();
//[骰子旋风]破坏对方场上的魔法陷阱
if
(
currentSolvingChain
!=
null
&&
currentLocation
==
(
int
)
CardLocation
.
Removed
)
List
<
ClientCard
>
ccards
=
new
List
<
ClientCard
>(
cards
);
bool
spellCard
=
true
;
List
<
ClientCard
>
enemyCards
=
new
List
<
ClientCard
>();
List
<
ClientCard
>
botCards
=
new
List
<
ClientCard
>();
foreach
(
ClientCard
card
in
ccards
)
{
{
i
f
(
card
==
null
)
continue
;
i
nt
originId
=
card
.
Id
;
if
(
!
card
.
HasType
(
CardType
.
Spell
)
&&
!
card
.
HasType
(
CardType
.
Trap
)
)
if
(
card
.
Data
!=
null
)
{
{
spellCard
=
false
;
if
(
card
.
Data
.
Alias
>
0
)
originId
=
card
.
Data
.
Alias
;
break
;
else
originId
=
card
.
Id
;
}
if
(
currentSolvingChain
.
IsCode
(
_CardId
.
CalledByTheGrave
))
{
calledbytheGraveIdCountMap
[
originId
]
=
2
;
}
if
(
currentSolvingChain
.
IsCode
(
_CardId
.
CrossoutDesignator
))
{
crossoutDesignatorIdList
.
Add
(
originId
);
}
}
}
base
.
OnMove
(
card
,
previousControler
,
previousLocation
,
currentControler
,
currentLocation
);
}
/// <summary>
/// Destroy face-down cards first, in our turn.
/// </summary>
protected
bool
DefaultMysticalSpaceTyphoon
()
{
if
(
Duel
.
CurrentChain
.
Any
(
card
=>
card
.
IsCode
(
_CardId
.
MysticalSpaceTyphoon
)))
{
return
false
;
}
List
<
ClientCard
>
spells
=
Enemy
.
GetSpells
();
if
(
spells
.
Count
==
0
)
return
false
;
ClientCard
selected
=
Enemy
.
SpellZone
.
GetFloodgate
();
if
(
selected
==
null
)
{
if
(
Duel
.
Player
==
0
)
selected
=
spells
.
FirstOrDefault
(
card
=>
card
.
IsFacedown
());
if
(
Duel
.
Player
==
1
)
selected
=
spells
.
FirstOrDefault
(
card
=>
card
.
HasType
(
CardType
.
Continuous
)
||
card
.
HasType
(
CardType
.
Equip
)
||
card
.
HasType
(
CardType
.
Field
));
}
if
(
selected
==
null
)
return
false
;
AI
.
SelectCard
(
selected
);
return
true
;
}
/// <summary>
/// Destroy face-down cards first, in our turn.
/// </summary>
protected
bool
DefaultCosmicCyclone
()
{
foreach
(
ClientCard
card
in
Duel
.
CurrentChain
)
if
(
card
.
IsCode
(
_CardId
.
CosmicCyclone
))
return
false
;
return
(
Bot
.
LifePoints
>
1000
)
&&
DefaultMysticalSpaceTyphoon
();
}
/// <summary>
/// Activate if avail.
/// </summary>
protected
bool
DefaultGalaxyCyclone
()
{
List
<
ClientCard
>
spells
=
Enemy
.
GetSpells
();
if
(
spells
.
Count
==
0
)
return
false
;
ClientCard
selected
=
null
;
if
(
Card
.
Location
==
CardLocation
.
Grave
)
{
selected
=
Util
.
GetBestEnemySpell
(
true
);
}
else
{
selected
=
spells
.
FirstOrDefault
(
card
=>
card
.
IsFacedown
());
}
if
(
selected
==
null
)
return
false
;
AI
.
SelectCard
(
selected
);
return
true
;
}
/// <summary>
/// Set the highest ATK level 4+ effect enemy monster.
/// </summary>
protected
bool
DefaultBookOfMoon
()
{
if
(
Util
.
IsAllEnemyBetter
(
true
))
{
ClientCard
monster
=
Enemy
.
GetMonsters
().
GetHighestAttackMonster
(
true
);
if
(
monster
!=
null
&&
monster
.
HasType
(
CardType
.
Effect
)
&&
!
monster
.
HasType
(
CardType
.
Link
)
&&
(
monster
.
HasType
(
CardType
.
Xyz
)
||
monster
.
Level
>
4
))
{
AI
.
SelectCard
(
monster
);
return
true
;
}
}
return
false
;
}
/// <summary>
/// Return problematic monster, and if this card become target, return any enemy monster.
/// </summary>
protected
bool
DefaultCompulsoryEvacuationDevice
()
{
ClientCard
target
=
Util
.
GetProblematicEnemyMonster
(
0
,
true
);
if
(
target
!=
null
)
{
AI
.
SelectCard
(
target
);
return
true
;
}
if
(
Util
.
IsChainTarget
(
Card
))
{
ClientCard
monster
=
Util
.
GetBestEnemyMonster
(
false
,
true
);
if
(
monster
!=
null
)
{
AI
.
SelectCard
(
monster
);
return
true
;
}
}
return
false
;
}
/// <summary>
/// Revive the best monster when we don't have better one in field.
/// </summary>
protected
bool
DefaultCallOfTheHaunted
()
{
if
(!
Util
.
IsAllEnemyBetter
(
true
))
return
false
;
ClientCard
selected
=
Bot
.
Graveyard
.
GetMatchingCards
(
card
=>
card
.
IsCanRevive
()).
OrderByDescending
(
card
=>
card
.
Attack
).
FirstOrDefault
();
AI
.
SelectCard
(
selected
);
return
true
;
}
/// <summary>
/// Default Scapegoat effect
/// </summary>
protected
bool
DefaultScapegoat
()
{
if
(
DefaultSpellWillBeNegated
())
return
false
;
if
(
Duel
.
Player
==
0
)
return
false
;
if
(
Duel
.
Phase
==
DuelPhase
.
End
)
return
true
;
if
(
DefaultOnBecomeTarget
())
return
true
;
if
(
Duel
.
Phase
>
DuelPhase
.
Main1
&&
Duel
.
Phase
<
DuelPhase
.
Main2
)
{
if
(
Enemy
.
HasInMonstersZone
(
new
[]
{
_CardId
.
UltimateConductorTytanno
,
_CardId
.
InvokedPurgatrio
,
_CardId
.
ChaosAncientGearGiant
,
_CardId
.
UltimateAncientGearGolem
,
_CardId
.
RedDragonArchfiend
},
true
))
return
false
;
if
(
Util
.
GetTotalAttackingMonsterAttack
(
1
)
>=
Bot
.
LifePoints
)
return
true
;
}
return
false
;
}
/// <summary>
/// Always active in opponent's turn.
/// </summary>
protected
bool
DefaultMaxxC
()
{
if
(
DefaultCheckWhetherCardIsNegated
(
Card
))
return
false
;
return
Duel
.
Player
==
1
;
}
/// <summary>
/// Always disable opponent's effect except some cards like UpstartGoblin
/// </summary>
protected
bool
DefaultAshBlossomAndJoyousSpring
()
{
if
(
DefaultCheckWhetherCardIsNegated
(
Card
))
return
false
;
int
[]
ignoreList
=
{
_CardId
.
MacroCosmos
,
_CardId
.
UpstartGoblin
,
_CardId
.
CyberEmergency
,
_CardId
.
TheAgentOfCreationVenus
};
if
(
Util
.
GetLastChainCard
().
IsCode
(
ignoreList
))
return
false
;
if
(
Util
.
GetLastChainCard
().
HasSetcode
(
0x11e
)
&&
Util
.
GetLastChainCard
().
Location
==
CardLocation
.
Hand
)
// Danger! archtype hand effect
return
false
;
return
Duel
.
LastChainPlayer
==
1
;
}
/// <summary>
/// Always activate unless the activating card is disabled
/// </summary>
protected
bool
DefaultGhostOgreAndSnowRabbit
()
{
if
(
DefaultCheckWhetherCardIsNegated
(
Card
))
return
false
;
if
(
Util
.
GetLastChainCard
()
!=
null
&&
Util
.
GetLastChainCard
().
IsDisabled
())
return
false
;
return
DefaultTrap
();
}
/// <summary>
/// Always disable opponent's effect
/// </summary>
protected
bool
DefaultGhostBelleAndHauntedMansion
()
{
if
(
DefaultCheckWhetherCardIsNegated
(
Card
))
return
false
;
return
DefaultTrap
();
}
/// <summary>
/// Same as DefaultBreakthroughSkill
/// </summary>
protected
bool
DefaultEffectVeiler
()
{
if
(
DefaultCheckWhetherCardIsNegated
(
Card
))
return
false
;
ClientCard
LastChainCard
=
Util
.
GetLastChainCard
();
if
(
LastChainCard
!=
null
&&
(
LastChainCard
.
IsCode
(
_CardId
.
GalaxySoldier
)
&&
Enemy
.
Hand
.
Count
>=
3
||
LastChainCard
.
IsCode
(
_CardId
.
EffectVeiler
,
_CardId
.
InfiniteImpermanence
)))
return
false
;
return
DefaultBreakthroughSkill
();
}
/// <summary>
/// Chain common hand traps
/// </summary>
protected
bool
DefaultCalledByTheGrave
()
{
int
[]
targetList
=
{
_CardId
.
MaxxC
,
_CardId
.
LockBird
,
_CardId
.
GhostOgreAndSnowRabbit
,
_CardId
.
AshBlossom
,
_CardId
.
GhostBelle
,
_CardId
.
EffectVeiler
,
_CardId
.
ArtifactLancea
};
if
(
Duel
.
LastChainPlayer
==
1
)
{
foreach
(
int
id
in
targetList
)
{
if
(
Util
.
GetLastChainCard
().
IsCode
(
id
))
{
AI
.
SelectCard
(
id
);
return
UniqueFaceupSpell
();
}
}
if
(
card
.
Controller
==
1
)
enemyCards
.
Add
(
card
);
}
else
botCards
.
Add
(
card
);
}
}
return
false
;
if
(
spellCard
)
}
/// <summary>
/// Default InfiniteImpermanence effect
/// </summary>
protected
bool
DefaultInfiniteImpermanence
()
{
if
(
DefaultCheckWhetherCardIsNegated
(
Card
))
return
false
;
// TODO: disable s & t
ClientCard
LastChainCard
=
Util
.
GetLastChainCard
();
if
(
LastChainCard
!=
null
&&
(
LastChainCard
.
IsCode
(
_CardId
.
GalaxySoldier
)
&&
Enemy
.
Hand
.
Count
>=
3
||
LastChainCard
.
IsCode
(
_CardId
.
EffectVeiler
,
_CardId
.
InfiniteImpermanence
)))
return
false
;
return
DefaultDisableMonster
();
}
/// <summary>
/// Chain the enemy monster, or disable monster like Rescue Rabbit.
/// </summary>
protected
bool
DefaultBreakthroughSkill
()
{
if
(!
DefaultUniqueTrap
())
return
false
;
return
DefaultDisableMonster
();
}
/// <summary>
/// Chain the enemy monster, or disable monster like Rescue Rabbit.
/// </summary>
protected
bool
DefaultDisableMonster
()
{
if
(
Duel
.
Player
==
1
)
{
ClientCard
target
=
Enemy
.
MonsterZone
.
GetShouldBeDisabledBeforeItUseEffectMonster
();
if
(
target
!=
null
)
{
{
enemyCards
.
AddRange
(
botCards
);
AI
.
SelectCard
(
target
);
return
Util
.
CheckSelectCount
(
enemyCards
,
cards
,
min
,
max
);
return
true
;
}
}
}
}
return
null
;
}
ClientCard
LastChainCard
=
Util
.
GetLastChainCard
();
public
override
void
OnReceivingAnnouce
(
int
player
,
int
data
)
if
(
LastChainCard
!=
null
&&
LastChainCard
.
Controller
==
1
&&
LastChainCard
.
Location
==
CardLocation
.
MonsterZone
&&
{
!
LastChainCard
.
IsDisabled
()
&&
!
LastChainCard
.
IsShouldNotBeTarget
()
&&
!
LastChainCard
.
IsShouldNotBeSpellTrapTarget
())
if
(
player
==
1
&&
data
==
Util
.
GetStringId
(
_CardId
.
LightningStorm
,
0
)
||
data
==
Util
.
GetStringId
(
_CardId
.
LightningStorm
,
1
))
{
{
AI
.
SelectCard
(
LastChainCard
);
lightningStormOption
=
data
-
Util
.
GetStringId
(
_CardId
.
LightningStorm
,
0
);
return
true
;
}
}
base
.
OnReceivingAnnouce
(
player
,
data
);
if
(
Bot
.
BattlingMonster
!=
null
&&
Enemy
.
BattlingMonster
!=
null
)
}
{
if
(!
Enemy
.
BattlingMonster
.
IsDisabled
()
&&
Enemy
.
BattlingMonster
.
IsCode
(
_CardId
.
EaterOfMillions
))
public
override
void
OnChainEnd
()
{
{
AI
.
SelectCard
(
Enemy
.
BattlingMonster
);
lightningStormOption
=
-
1
;
return
true
;
base
.
OnChainEnd
();
}
}
}
/// <summary>
if
(
Duel
.
Phase
==
DuelPhase
.
BattleStart
&&
Duel
.
Player
==
1
&&
/// Reset variables for new turn.
Enemy
.
HasInMonstersZone
(
_CardId
.
NumberS39UtopiaTheLightning
,
true
))
/// </summary>
{
public
override
void
OnNewTurn
()
AI
.
SelectCard
(
_CardId
.
NumberS39UtopiaTheLightning
);
{
return
true
;
if
(
Duel
.
Turn
<=
1
)
calledbytheGraveIdCountMap
.
Clear
();
}
List
<
int
>
keyList
=
calledbytheGraveIdCountMap
.
Keys
.
ToList
();
foreach
(
int
dic
in
keyList
)
return
false
;
{
}
if
(
calledbytheGraveIdCountMap
[
dic
]
>
0
)
{
/// <summary>
calledbytheGraveIdCountMap
[
dic
]
-=
1
;
/// Activate only except this card is the target or we summon monsters.
}
/// </summary>
}
protected
bool
DefaultSolemnJudgment
()
crossoutDesignatorIdList
.
Clear
();
{
return
!
Util
.
IsChainTargetOnly
(
Card
)
&&
!(
Duel
.
Player
==
0
&&
Duel
.
LastChainPlayer
==
-
1
)
&&
!
DefaultOnlyHorusSpSummoning
()
&&
DefaultTrap
();
base
.
OnNewTurn
();
}
}
/// <summary>
public
override
void
OnMove
(
ClientCard
card
,
int
previousControler
,
int
previousLocation
,
int
currentControler
,
int
currentLocation
)
/// Activate only except we summon monsters.
{
/// </summary>
if
(
card
!=
null
)
protected
bool
DefaultSolemnWarning
()
{
{
ClientCard
currentSolvingChain
=
Duel
.
GetCurrentSolvingChainCard
();
return
(
Bot
.
LifePoints
>
2000
)
&&
!(
Duel
.
Player
==
0
&&
Duel
.
LastChainPlayer
==
-
1
)
&&
!
DefaultOnlyHorusSpSummoning
()
&&
DefaultTrap
();
if
(
currentSolvingChain
!=
null
&&
currentLocation
==
(
int
)
CardLocation
.
Removed
)
}
{
int
originId
=
card
.
Id
;
/// <summary>
if
(
card
.
Data
!=
null
)
/// Activate only except we summon monsters.
{
/// </summary>
if
(
card
.
Data
.
Alias
>
0
)
originId
=
card
.
Data
.
Alias
;
protected
bool
DefaultSolemnStrike
()
else
originId
=
card
.
Id
;
{
}
return
(
Bot
.
LifePoints
>
1500
)
&&
!(
Duel
.
Player
==
0
&&
Duel
.
LastChainPlayer
==
-
1
)
&&
!
DefaultOnlyHorusSpSummoning
()
&&
DefaultTrap
();
if
(
currentSolvingChain
.
IsCode
(
_CardId
.
CalledByTheGrave
))
}
{
calledbytheGraveIdCountMap
[
originId
]
=
2
;
/// <summary>
}
/// Check whether only Horus monster is special summoning.
if
(
currentSolvingChain
.
IsCode
(
_CardId
.
CrossoutDesignator
))
/// If returning true, should not negate the special summon since it can be special summoned again.
{
/// </summary>
crossoutDesignatorIdList
.
Add
(
originId
);
/// <returns></returns>
}
protected
bool
DefaultOnlyHorusSpSummoning
()
}
{
}
if
(
Duel
.
SummoningCards
.
Count
!=
0
)
base
.
OnMove
(
card
,
previousControler
,
previousLocation
,
currentControler
,
currentLocation
);
{
}
bool
notOnlyHorusFlag
=
false
;
foreach
(
ClientCard
card
in
Duel
.
SummoningCards
)
/// <summary>
{
/// Destroy face-down cards first, in our turn.
if
(!
card
.
HasSetcode
(
_Setcode
.
Horus
)
||
card
.
LastLocation
!=
CardLocation
.
Grave
)
/// </summary>
{
protected
bool
DefaultMysticalSpaceTyphoon
()
notOnlyHorusFlag
=
true
;
{
break
;
if
(
Duel
.
CurrentChain
.
Any
(
card
=>
card
.
IsCode
(
_CardId
.
MysticalSpaceTyphoon
)))
}
{
}
return
false
;
return
!
notOnlyHorusFlag
;
}
}
return
false
;
List
<
ClientCard
>
spells
=
Enemy
.
GetSpells
();
}
if
(
spells
.
Count
==
0
)
return
false
;
/// <summary>
/// Activate when all enemy monsters have better ATK.
ClientCard
selected
=
Enemy
.
SpellZone
.
GetFloodgate
();
/// </summary>
protected
bool
DefaultTorrentialTribute
()
if
(
selected
==
null
)
{
{
return
!
Util
.
HasChainedTrap
(
0
)
&&
Util
.
IsAllEnemyBetter
(
true
);
if
(
Duel
.
Player
==
0
)
}
selected
=
spells
.
FirstOrDefault
(
card
=>
card
.
IsFacedown
());
if
(
Duel
.
Player
==
1
)
/// <summary>
selected
=
spells
.
FirstOrDefault
(
card
=>
card
.
HasType
(
CardType
.
Continuous
)
||
card
.
HasType
(
CardType
.
Equip
)
||
card
.
HasType
(
CardType
.
Field
));
/// Activate enemy have more S&T.
}
/// </summary>
protected
bool
DefaultHeavyStorm
()
if
(
selected
==
null
)
{
return
false
;
return
Bot
.
GetSpellCount
()
<
Enemy
.
GetSpellCount
();
AI
.
SelectCard
(
selected
);
}
return
true
;
}
/// <summary>
/// Activate before other winds, if enemy have more than 2 S&T.
/// <summary>
/// </summary>
/// Destroy face-down cards first, in our turn.
protected
bool
DefaultHarpiesFeatherDusterFirst
()
/// </summary>
{
protected
bool
DefaultCosmicCyclone
()
return
Enemy
.
GetSpellCount
()
>=
2
;
{
}
foreach
(
ClientCard
card
in
Duel
.
CurrentChain
)
if
(
card
.
IsCode
(
_CardId
.
CosmicCyclone
))
/// <summary>
return
false
;
/// Activate when one enemy monsters have better ATK.
return
(
Bot
.
LifePoints
>
1000
)
&&
DefaultMysticalSpaceTyphoon
();
/// </summary>
}
protected
bool
DefaultHammerShot
()
{
/// <summary>
return
Util
.
IsOneEnemyBetter
(
true
);
/// Activate if avail.
}
/// </summary>
protected
bool
DefaultGalaxyCyclone
()
/// <summary>
{
/// Activate when one enemy monsters have better ATK or DEF.
List
<
ClientCard
>
spells
=
Enemy
.
GetSpells
();
/// </summary>
if
(
spells
.
Count
==
0
)
protected
bool
DefaultDarkHole
()
return
false
;
{
return
Util
.
IsOneEnemyBetter
();
ClientCard
selected
=
null
;
}
if
(
Card
.
Location
==
CardLocation
.
Grave
)
/// <summary>
{
/// Activate when one enemy monsters have better ATK or DEF.
selected
=
Util
.
GetBestEnemySpell
(
true
);
/// </summary>
}
protected
bool
DefaultRaigeki
()
else
{
{
return
Util
.
IsOneEnemyBetter
();
selected
=
spells
.
FirstOrDefault
(
card
=>
card
.
IsFacedown
());
}
}
/// <summary>
if
(
selected
==
null
)
/// Activate when one enemy monsters have better ATK or DEF.
return
false
;
/// </summary>
protected
bool
DefaultSmashingGround
()
AI
.
SelectCard
(
selected
);
{
return
true
;
return
Util
.
IsOneEnemyBetter
();
}
}
/// <summary>
/// <summary>
/// Set the highest ATK level 4+ effect enemy monster.
/// Activate when we have more than 15 cards in deck.
/// </summary>
/// </summary>
protected
bool
DefaultBookOfMoon
()
protected
bool
DefaultPotOfDesires
()
{
{
if
(
Util
.
IsAllEnemyBetter
(
true
))
return
Bot
.
Deck
.
Count
>
15
;
{
}
ClientCard
monster
=
Enemy
.
GetMonsters
().
GetHighestAttackMonster
(
true
);
if
(
monster
!=
null
&&
monster
.
HasType
(
CardType
.
Effect
)
&&
!
monster
.
HasType
(
CardType
.
Link
)
&&
(
monster
.
HasType
(
CardType
.
Xyz
)
||
monster
.
Level
>
4
))
/// <summary>
{
/// Set traps only and avoid block the activation of other cards.
AI
.
SelectCard
(
monster
);
/// </summary>
return
true
;
protected
bool
DefaultSpellSet
()
}
{
}
return
(
Card
.
IsTrap
()
||
Card
.
HasType
(
CardType
.
QuickPlay
)
||
DefaultSpellMustSetFirst
())
&&
Bot
.
GetSpellCountWithoutField
()
<
4
;
return
false
;
}
}
/// <summary>
/// <summary>
/// Summon with no tribute, or with tributes ATK lower.
/// Return problematic monster, and if this card become target, return any enemy monster.
/// </summary>
/// </summary>
protected
bool
DefaultMonsterSummon
()
protected
bool
DefaultCompulsoryEvacuationDevice
()
{
{
if
(
Card
.
Level
<=
4
)
ClientCard
target
=
Util
.
GetProblematicEnemyMonster
(
0
,
true
);
return
true
;
if
(
target
!=
null
)
{
if
(!
UniqueFaceupMonster
())
AI
.
SelectCard
(
target
);
return
false
;
return
true
;
int
tributecount
=
(
int
)
Math
.
Ceiling
((
Card
.
Level
-
4.0d
)
/
2.0d
);
}
for
(
int
j
=
0
;
j
<
7
;
++
j
)
if
(
Util
.
IsChainTarget
(
Card
))
{
{
ClientCard
tributeCard
=
Bot
.
MonsterZone
[
j
];
ClientCard
monster
=
Util
.
GetBestEnemyMonster
(
false
,
true
);
if
(
tributeCard
==
null
)
continue
;
if
(
monster
!=
null
)
if
(
tributeCard
.
GetDefensePower
()
<
Card
.
Attack
)
{
tributecount
--;
AI
.
SelectCard
(
monster
);
}
return
true
;
return
tributecount
<=
0
;
}
}
}
return
false
;
/// <summary>
}
/// Activate when we have no field.
/// </summary>
/// <summary>
protected
bool
DefaultField
()
/// Revive the best monster when we don't have better one in field.
{
/// </summary>
return
Bot
.
SpellZone
[
5
]
==
null
;
protected
bool
DefaultCallOfTheHaunted
()
}
{
if
(!
Util
.
IsAllEnemyBetter
(
true
))
/// <summary>
return
false
;
/// Turn if all enemy is better.
ClientCard
selected
=
Bot
.
Graveyard
.
GetMatchingCards
(
card
=>
card
.
IsCanRevive
()).
OrderByDescending
(
card
=>
card
.
Attack
).
FirstOrDefault
();
/// </summary>
AI
.
SelectCard
(
selected
);
protected
bool
DefaultMonsterRepos
()
return
true
;
{
}
if
(
Card
.
IsMonsterInvincible
())
return
Card
.
IsDefense
();
/// <summary>
/// Default Scapegoat effect
if
(
Card
.
Attack
==
0
)
/// </summary>
{
protected
bool
DefaultScapegoat
()
if
(
Card
.
IsFaceup
()
&&
Card
.
IsAttack
())
{
return
true
;
if
(
DefaultSpellWillBeNegated
())
return
false
;
if
(
Card
.
IsFaceup
()
&&
Card
.
IsDefense
())
if
(
Duel
.
Player
==
0
)
return
false
;
return
false
;
if
(
Duel
.
Phase
==
DuelPhase
.
End
)
return
true
;
}
if
(
DefaultOnBecomeTarget
())
return
true
;
if
(
Duel
.
Phase
>
DuelPhase
.
Main1
&&
Duel
.
Phase
<
DuelPhase
.
Main2
)
if
(
Enemy
.
HasInMonstersZone
(
_CardId
.
BlueEyesChaosMAXDragon
,
true
)
&&
{
Card
.
IsAttack
()
&&
(
4000
-
Card
.
Defense
)
*
2
>
(
4000
-
Card
.
Attack
))
if
(
Enemy
.
HasInMonstersZone
(
new
[]
return
false
;
{
if
(
Enemy
.
HasInMonstersZone
(
_CardId
.
BlueEyesChaosMAXDragon
,
true
)
&&
_CardId
.
UltimateConductorTytanno
,
Card
.
IsDefense
()
&&
Card
.
IsFaceup
()
&&
_CardId
.
InvokedPurgatrio
,
(
4000
-
Card
.
Defense
)
*
2
>
(
4000
-
Card
.
Attack
))
_CardId
.
ChaosAncientGearGiant
,
return
true
;
_CardId
.
UltimateAncientGearGolem
,
_CardId
.
RedDragonArchfiend
bool
enemyBetter
=
Util
.
IsAllEnemyBetter
();
},
true
))
return
false
;
if
(
Card
.
IsAttack
()
&&
enemyBetter
)
if
(
Util
.
GetTotalAttackingMonsterAttack
(
1
)
>=
Bot
.
LifePoints
)
return
true
;
return
true
;
}
if
(
Card
.
IsDefense
()
&&
!
enemyBetter
&&
(
Card
.
Attack
>=
Card
.
Defense
||
Card
.
Attack
>=
Util
.
GetBestPower
(
Enemy
)))
return
false
;
return
true
;
}
/// <summary>
return
false
;
/// Always active in opponent's turn.
}
/// </summary>
protected
bool
DefaultMaxxC
()
/// <summary>
{
/// If spell will be negated
if
(
DefaultCheckWhetherCardIsNegated
(
Card
))
return
false
;
/// </summary>
return
Duel
.
Player
==
1
;
protected
bool
DefaultSpellWillBeNegated
()
}
{
/// <summary>
return
(
Bot
.
HasInSpellZone
(
_CardId
.
ImperialOrder
,
true
,
true
)
||
Enemy
.
HasInSpellZone
(
_CardId
.
ImperialOrder
,
true
))
&&
!
Util
.
ChainContainsCard
(
_CardId
.
ImperialOrder
)
/// Always disable opponent's effect except some cards like UpstartGoblin
||
DefaultCheckWhetherCardIsNegated
(
Card
);
/// </summary>
}
protected
bool
DefaultAshBlossomAndJoyousSpring
()
{
/// <summary>
if
(
DefaultCheckWhetherCardIsNegated
(
Card
))
return
false
;
/// If trap will be negated
int
[]
ignoreList
=
{
/// </summary>
_CardId
.
MacroCosmos
,
protected
bool
DefaultTrapWillBeNegated
()
_CardId
.
UpstartGoblin
,
{
_CardId
.
CyberEmergency
,
return
(
Bot
.
HasInSpellZone
(
_CardId
.
RoyalDecreel
,
true
,
true
)
||
Enemy
.
HasInSpellZone
(
_CardId
.
RoyalDecreel
,
true
))
&&
!
Util
.
ChainContainsCard
(
_CardId
.
RoyalDecreel
)
_CardId
.
TheAgentOfCreationVenus
||
DefaultCheckWhetherCardIsNegated
(
Card
);
};
}
if
(
Util
.
GetLastChainCard
().
IsCode
(
ignoreList
))
return
false
;
/// <summary>
if
(
Util
.
GetLastChainCard
().
HasSetcode
(
0x11e
)
&&
Util
.
GetLastChainCard
().
Location
==
CardLocation
.
Hand
)
// Danger! archtype hand effect
/// If spell must set first to activate
return
false
;
/// </summary>
return
Duel
.
LastChainPlayer
==
1
;
protected
bool
DefaultSpellMustSetFirst
()
}
{
/// <summary>
return
Bot
.
HasInSpellZone
(
_CardId
.
AntiSpellFragrance
,
true
,
true
)
||
Enemy
.
HasInSpellZone
(
_CardId
.
AntiSpellFragrance
,
true
);
/// Always activate unless the activating card is disabled
}
/// </summary>
protected
bool
DefaultGhostOgreAndSnowRabbit
()
/// <summary>
{
/// if spell/trap is the target or enermy activate HarpiesFeatherDuster
if
(
DefaultCheckWhetherCardIsNegated
(
Card
))
return
false
;
/// </summary>
if
(
Util
.
GetLastChainCard
()
!=
null
&&
Util
.
GetLastChainCard
().
IsDisabled
())
protected
bool
DefaultOnBecomeTarget
()
return
false
;
{
return
DefaultTrap
();
if
(
Util
.
IsChainTarget
(
Card
))
return
true
;
}
int
[]
destroyAllList
=
/// <summary>
{
/// Always disable opponent's effect
_CardId
.
EvilswarmExcitonKnight
,
/// </summary>
_CardId
.
BlackRoseDragon
,
protected
bool
DefaultGhostBelleAndHauntedMansion
()
_CardId
.
JudgmentDragon
,
{
_CardId
.
TopologicTrisbaena
,
if
(
DefaultCheckWhetherCardIsNegated
(
Card
))
return
false
;
_CardId
.
EvenlyMatched
,
return
DefaultTrap
();
_CardId
.
DivineArsenalAAZEUS_SkyThunder
}
};
/// <summary>
int
[]
destroyAllMonsterList
=
/// Same as DefaultBreakthroughSkill
{
/// </summary>
_CardId
.
DarkHole
,
protected
bool
DefaultEffectVeiler
()
_CardId
.
InterruptedKaijuSlumber
{
};
if
(
DefaultCheckWhetherCardIsNegated
(
Card
))
return
false
;
int
[]
destroyAllOpponentMonsterList
=
ClientCard
LastChainCard
=
Util
.
GetLastChainCard
();
{
if
(
LastChainCard
!=
null
&&
(
LastChainCard
.
IsCode
(
_CardId
.
GalaxySoldier
)
&&
Enemy
.
Hand
.
Count
>=
3
_CardId
.
Raigeki
||
LastChainCard
.
IsCode
(
_CardId
.
EffectVeiler
,
_CardId
.
InfiniteImpermanence
)))
};
return
false
;
int
[]
destroyAllOpponentSpellList
=
return
DefaultBreakthroughSkill
();
{
}
_CardId
.
HarpiesFeatherDuster
,
/// <summary>
_CardId
.
DarkMagicAttack
/// Chain common hand traps
};
/// </summary>
protected
bool
DefaultCalledByTheGrave
()
if
(
Util
.
ChainContainsCard
(
destroyAllList
))
return
true
;
{
if
(
Enemy
.
HasInSpellZone
(
destroyAllOpponentSpellList
,
true
)
&&
Card
.
Location
==
CardLocation
.
SpellZone
)
return
true
;
int
[]
targetList
=
if
(
Util
.
ChainContainsCard
(
destroyAllMonsterList
)
&&
Card
.
Location
==
CardLocation
.
MonsterZone
)
return
true
;
{
if
(
Duel
.
CurrentChain
.
Any
(
c
=>
c
.
Controller
==
1
&&
c
.
IsCode
(
destroyAllOpponentMonsterList
))
&&
Card
.
Location
==
CardLocation
.
MonsterZone
)
return
true
;
_CardId
.
MaxxC
,
if
(
lightningStormOption
==
0
&&
Card
.
Location
==
CardLocation
.
MonsterZone
&&
Card
.
IsAttack
())
return
true
;
_CardId
.
LockBird
,
if
(
lightningStormOption
==
1
&&
Card
.
Location
==
CardLocation
.
SpellZone
)
return
true
;
_CardId
.
GhostOgreAndSnowRabbit
,
// TODO: ChainContainsCard(id, player)
_CardId
.
AshBlossom
,
return
false
;
_CardId
.
GhostBelle
,
}
_CardId
.
EffectVeiler
,
/// <summary>
_CardId
.
ArtifactLancea
/// Chain enemy activation or summon.
};
/// </summary>
if
(
Duel
.
LastChainPlayer
==
1
)
protected
bool
DefaultTrap
()
{
{
foreach
(
int
id
in
targetList
)
if
(
DefaultCheckWhetherCardIsNegated
(
Card
))
return
false
;
{
return
(
Duel
.
LastChainPlayer
==
-
1
&&
Duel
.
LastSummonPlayer
!=
0
)
||
Duel
.
LastChainPlayer
==
1
;
if
(
Util
.
GetLastChainCard
().
IsCode
(
id
))
}
{
AI
.
SelectCard
(
id
);
/// <summary>
return
UniqueFaceupSpell
();
/// Activate when avail and no other our trap card in this chain or face-up.
}
/// </summary>
}
protected
bool
DefaultUniqueTrap
()
}
{
return
false
;
if
(
Util
.
HasChainedTrap
(
0
))
}
return
false
;
/// <summary>
/// Default InfiniteImpermanence effect
return
UniqueFaceupSpell
();
/// </summary>
}
protected
bool
DefaultInfiniteImpermanence
()
{
/// <summary>
if
(
DefaultCheckWhetherCardIsNegated
(
Card
))
return
false
;
/// Check no other our spell or trap card with same name face-up.
// TODO: disable s & t
/// </summary>
ClientCard
LastChainCard
=
Util
.
GetLastChainCard
();
protected
bool
UniqueFaceupSpell
()
if
(
LastChainCard
!=
null
&&
(
LastChainCard
.
IsCode
(
_CardId
.
GalaxySoldier
)
&&
Enemy
.
Hand
.
Count
>=
3
{
||
LastChainCard
.
IsCode
(
_CardId
.
EffectVeiler
,
_CardId
.
InfiniteImpermanence
)))
return
!
Bot
.
GetSpells
().
Any
(
card
=>
card
.
IsCode
(
Card
.
Id
)
&&
card
.
IsFaceup
());
return
false
;
}
return
DefaultDisableMonster
();
}
/// <summary>
/// <summary>
/// Check no other our monster card with same name face-up.
/// Chain the enemy monster, or disable monster like Rescue Rabbit.
/// </summary>
/// </summary>
protected
bool
UniqueFaceupMonster
()
protected
bool
DefaultBreakthroughSkill
()
{
{
return
!
Bot
.
GetMonsters
().
Any
(
card
=>
card
.
IsCode
(
Card
.
Id
)
&&
card
.
IsFaceup
());
if
(!
DefaultUniqueTrap
())
}
return
false
;
return
DefaultDisableMonster
();
/// <summary>
}
/// Dumb way to avoid the bot chain in mess.
/// <summary>
/// </summary>
/// Chain the enemy monster, or disable monster like Rescue Rabbit.
protected
bool
DefaultDontChainMyself
()
/// </summary>
{
protected
bool
DefaultDisableMonster
()
if
(
Type
!=
ExecutorType
.
Activate
)
{
return
true
;
if
(
Duel
.
Player
==
1
)
if
(
Executors
.
Any
(
exec
=>
exec
.
Type
==
Type
&&
exec
.
CardId
==
Card
.
Id
))
{
return
false
;
ClientCard
target
=
Enemy
.
MonsterZone
.
GetShouldBeDisabledBeforeItUseEffectMonster
();
return
Duel
.
LastChainPlayer
!=
0
;
if
(
target
!=
null
)
}
{
AI
.
SelectCard
(
target
);
/// <summary>
return
true
;
/// Draw when we have lower LP, or destroy it. Can be overrided.
}
/// </summary>
}
protected
bool
DefaultChickenGame
()
{
ClientCard
LastChainCard
=
Util
.
GetLastChainCard
();
if
(
Executors
.
Count
(
exec
=>
exec
.
Type
==
Type
&&
exec
.
CardId
==
Card
.
Id
)
>
1
)
return
false
;
if
(
LastChainCard
!=
null
&&
LastChainCard
.
Controller
==
1
&&
LastChainCard
.
Location
==
CardLocation
.
MonsterZone
&&
if
(
Card
.
IsFacedown
())
!
LastChainCard
.
IsDisabled
()
&&
!
LastChainCard
.
IsShouldNotBeTarget
()
&&
!
LastChainCard
.
IsShouldNotBeSpellTrapTarget
())
return
true
;
{
if
(
Bot
.
LifePoints
<=
1000
)
AI
.
SelectCard
(
LastChainCard
);
return
false
;
return
true
;
if
(
Bot
.
LifePoints
<=
Enemy
.
LifePoints
&&
ActivateDescription
==
Util
.
GetStringId
(
_CardId
.
ChickenGame
,
0
))
}
if
(
Bot
.
BattlingMonster
!=
null
&&
Enemy
.
BattlingMonster
!=
null
)
{
if
(!
Enemy
.
BattlingMonster
.
IsDisabled
()
&&
Enemy
.
BattlingMonster
.
IsCode
(
_CardId
.
EaterOfMillions
))
{
AI
.
SelectCard
(
Enemy
.
BattlingMonster
);
return
true
;
}
}
if
(
Duel
.
Phase
==
DuelPhase
.
BattleStart
&&
Duel
.
Player
==
1
&&
Enemy
.
HasInMonstersZone
(
_CardId
.
NumberS39UtopiaTheLightning
,
true
))
{
AI
.
SelectCard
(
_CardId
.
NumberS39UtopiaTheLightning
);
return
true
;
}
return
false
;
}
/// <summary>
/// Activate only except this card is the target or we summon monsters.
/// </summary>
protected
bool
DefaultSolemnJudgment
()
{
return
!
Util
.
IsChainTargetOnly
(
Card
)
&&
!(
Duel
.
Player
==
0
&&
Duel
.
LastChainPlayer
==
-
1
)
&&
!
DefaultOnlyHorusSpSummoning
()
&&
DefaultTrap
();
}
/// <summary>
/// Activate only except we summon monsters.
/// </summary>
protected
bool
DefaultSolemnWarning
()
{
return
(
Bot
.
LifePoints
>
2000
)
&&
!(
Duel
.
Player
==
0
&&
Duel
.
LastChainPlayer
==
-
1
)
&&
!
DefaultOnlyHorusSpSummoning
()
&&
DefaultTrap
();
}
/// <summary>
/// Activate only except we summon monsters.
/// </summary>
protected
bool
DefaultSolemnStrike
()
{
return
(
Bot
.
LifePoints
>
1500
)
&&
!(
Duel
.
Player
==
0
&&
Duel
.
LastChainPlayer
==
-
1
)
&&
!
DefaultOnlyHorusSpSummoning
()
&&
DefaultTrap
();
}
/// <summary>
/// Check whether only Horus monster is special summoning.
/// If returning true, should not negate the special summon since it can be special summoned again.
/// </summary>
/// <returns></returns>
protected
bool
DefaultOnlyHorusSpSummoning
()
{
if
(
Duel
.
SummoningCards
.
Count
!=
0
)
{
bool
notOnlyHorusFlag
=
false
;
foreach
(
ClientCard
card
in
Duel
.
SummoningCards
)
{
if
(!
card
.
HasSetcode
(
_Setcode
.
Horus
)
||
card
.
LastLocation
!=
CardLocation
.
Grave
)
{
notOnlyHorusFlag
=
true
;
break
;
}
}
return
!
notOnlyHorusFlag
;
}
return
false
;
}
/// <summary>
/// Activate when all enemy monsters have better ATK.
/// </summary>
protected
bool
DefaultTorrentialTribute
()
{
return
!
Util
.
HasChainedTrap
(
0
)
&&
Util
.
IsAllEnemyBetter
(
true
);
}
/// <summary>
/// Activate enemy have more S&T.
/// </summary>
protected
bool
DefaultHeavyStorm
()
{
return
Bot
.
GetSpellCount
()
<
Enemy
.
GetSpellCount
();
}
/// <summary>
/// Activate before other winds, if enemy have more than 2 S&T.
/// </summary>
protected
bool
DefaultHarpiesFeatherDusterFirst
()
{
return
Enemy
.
GetSpellCount
()
>=
2
;
}
/// <summary>
/// Activate when one enemy monsters have better ATK.
/// </summary>
protected
bool
DefaultHammerShot
()
{
return
Util
.
IsOneEnemyBetter
(
true
);
}
/// <summary>
/// Activate when one enemy monsters have better ATK or DEF.
/// </summary>
protected
bool
DefaultDarkHole
()
{
return
Util
.
IsOneEnemyBetter
();
}
/// <summary>
/// Activate when one enemy monsters have better ATK or DEF.
/// </summary>
protected
bool
DefaultRaigeki
()
{
return
Util
.
IsOneEnemyBetter
();
}
/// <summary>
/// Activate when one enemy monsters have better ATK or DEF.
/// </summary>
protected
bool
DefaultSmashingGround
()
{
return
Util
.
IsOneEnemyBetter
();
}
/// <summary>
/// Activate when we have more than 15 cards in deck.
/// </summary>
protected
bool
DefaultPotOfDesires
()
{
return
Bot
.
Deck
.
Count
>
15
;
}
/// <summary>
/// Set traps only and avoid block the activation of other cards.
/// </summary>
protected
bool
DefaultSpellSet
()
{
if
(
Card
.
Id
==
15693423
)
return
false
;
if
(
Card
.
Id
==
9373534
)
return
true
;
return
(
Card
.
IsTrap
()
||
Card
.
HasType
(
CardType
.
QuickPlay
)
||
DefaultSpellMustSetFirst
())
&&
Bot
.
GetSpellCountWithoutField
()
<
4
;
}
/// <summary>
/// Summon with no tribute, or with tributes ATK lower.
/// </summary>
protected
bool
DefaultMonsterSummon
()
{
if
(
Card
.
Level
<=
4
)
return
true
;
if
(!
UniqueFaceupMonster
())
return
false
;
if
(
DontSummon
(
Card
))
return
false
;
int
tributecount
=
(
int
)
Math
.
Ceiling
((
Card
.
Level
-
4.0d
)
/
2.0d
);
for
(
int
j
=
0
;
j
<
7
;
++
j
)
{
ClientCard
tributeCard
=
Bot
.
MonsterZone
[
j
];
if
(
tributeCard
==
null
)
continue
;
if
(
tributeCard
.
GetDefensePower
()
<
Card
.
Attack
)
tributecount
--;
}
return
tributecount
<=
0
;
}
/// <summary>
/// Dont summon cards'id in the following list
/// </summary>
private
bool
DontSummon
(
ClientCard
card
)
{
if
(
card
.
HasSetcode
(
0x40
)
||
card
.
HasSetcode
(
0xa4
)
||
card
.
HasSetcode
(
0xd3
))
return
true
;
int
[]
cardsname
=
new
[]
{
74762582
,
90179822
,
16759958
,
26964762
,
42352091
,
2511
,
74018812
,
76214441
,
62886670
,
69105797
,
32391566
,
94076521
,
73625877
,
1980574
,
42090294
,
68823957
,
34976176
,
89785779
,
76133574
,
3248469
,
87102774
,
57647597
,
37961969
,
51993760
,
87988305
,
38339996
,
37629703
,
58131925
,
71133680
,
42790071
,
34475451
,
63009228
,
24725825
,
48427163
,
86028783
,
51852507
,
29280589
,
87462901
,
73640163
,
68120130
,
84813516
,
55461064
,
59042331
,
26775203
,
89169343
,
67750322
,
68819554
,
26084285
,
15613529
,
19096726
,
59546797
,
12235475
,
38695361
,
37742478
,
26914168
,
43534808
,
13313278
,
99581584
,
04192696
,
89662736
,
81109178
,
18444902
,
04807253
,
12423762
,
72318602
,
86613346
,
82489470
,
16223761
,
08152834
/*像是手坑的时尚小垃圾*/
,
97268402
/*效果遮蒙者*/
,
24508238
/*D.D.乌鸦*/
,
94145021
/*锁鸟*/
,
14558127
,
14558128
,
52038441
,
52038442
,
59438930
,
59438931
,
60643553
,
60643554
,
62015408
,
62015409
,
73642296
,
73642297
/*手坑六姐妹*/
,
15721123
,
23434538
,
25137581
,
46502744
,
80978111
,
87170768
,
94081496
/*xx的G*/
,
17266660
,
21074344
,
94689635
/*宣告者*/
,
18964575
,
20450925
,
19665973
,
28427869
,
27352108
/*攻宣坑*/
};
if
(
card
.
IsCode
(
cardsname
))
return
true
;
return
false
;
}
/// <summary>
/// Activate when we have no field.
/// </summary>
protected
bool
DefaultField
()
{
return
Bot
.
SpellZone
[
5
]
==
null
;
}
/// <summary>
/// Turn if all enemy is better.
/// </summary>
protected
bool
DefaultMonsterRepos
()
{
if
(
Card
.
IsMonsterInvincible
())
return
Card
.
IsDefense
();
if
(
Card
.
Attack
==
0
)
{
if
(
Card
.
IsFaceup
()
&&
Card
.
IsAttack
())
return
true
;
if
(
Card
.
IsFaceup
()
&&
Card
.
IsDefense
())
return
false
;
}
if
(
Enemy
.
HasInMonstersZone
(
_CardId
.
BlueEyesChaosMAXDragon
,
true
)
&&
Card
.
IsAttack
()
&&
(
4000
-
Card
.
Defense
)
*
2
>
(
4000
-
Card
.
Attack
))
return
false
;
if
(
Enemy
.
HasInMonstersZone
(
_CardId
.
BlueEyesChaosMAXDragon
,
true
)
&&
Card
.
IsDefense
()
&&
Card
.
IsFaceup
()
&&
(
4000
-
Card
.
Defense
)
*
2
>
(
4000
-
Card
.
Attack
))
return
true
;
bool
enemyBetter
=
Util
.
IsAllEnemyBetter
();
if
(
Card
.
IsAttack
()
&&
enemyBetter
)
return
true
;
if
(
Card
.
IsDefense
()
&&
!
enemyBetter
&&
(
Card
.
Attack
>=
Card
.
Defense
||
Card
.
Attack
>=
Util
.
GetBestPower
(
Enemy
)))
return
true
;
return
false
;
}
/// <summary>
/// If spell will be negated
/// </summary>
protected
bool
DefaultSpellWillBeNegated
()
{
return
(
Bot
.
HasInSpellZone
(
_CardId
.
ImperialOrder
,
true
,
true
)
||
Enemy
.
HasInSpellZone
(
_CardId
.
ImperialOrder
,
true
))
&&
!
Util
.
ChainContainsCard
(
_CardId
.
ImperialOrder
)
||
DefaultCheckWhetherCardIsNegated
(
Card
);
}
/// <summary>
/// If trap will be negated
/// </summary>
protected
bool
DefaultTrapWillBeNegated
()
{
return
(
Bot
.
HasInSpellZone
(
_CardId
.
RoyalDecreel
,
true
,
true
)
||
Enemy
.
HasInSpellZone
(
_CardId
.
RoyalDecreel
,
true
))
&&
!
Util
.
ChainContainsCard
(
_CardId
.
RoyalDecreel
)
||
DefaultCheckWhetherCardIsNegated
(
Card
);
}
/// <summary>
/// If spell must set first to activate
/// </summary>
protected
bool
DefaultSpellMustSetFirst
()
{
return
Bot
.
HasInSpellZone
(
_CardId
.
AntiSpellFragrance
,
true
,
true
)
||
Enemy
.
HasInSpellZone
(
_CardId
.
AntiSpellFragrance
,
true
);
}
/// <summary>
/// if spell/trap is the target or enermy activate HarpiesFeatherDuster
/// </summary>
protected
bool
DefaultOnBecomeTarget
()
{
if
(
Util
.
IsChainTarget
(
Card
))
return
true
;
int
[]
destroyAllList
=
{
_CardId
.
EvilswarmExcitonKnight
,
_CardId
.
BlackRoseDragon
,
_CardId
.
JudgmentDragon
,
_CardId
.
TopologicTrisbaena
,
_CardId
.
EvenlyMatched
,
_CardId
.
DivineArsenalAAZEUS_SkyThunder
};
int
[]
destroyAllMonsterList
=
{
_CardId
.
DarkHole
,
_CardId
.
InterruptedKaijuSlumber
};
int
[]
destroyAllOpponentMonsterList
=
{
_CardId
.
Raigeki
};
int
[]
destroyAllOpponentSpellList
=
{
_CardId
.
HarpiesFeatherDuster
,
_CardId
.
DarkMagicAttack
};
if
(
Util
.
ChainContainsCard
(
destroyAllList
))
return
true
;
if
(
Enemy
.
HasInSpellZone
(
destroyAllOpponentSpellList
,
true
)
&&
Card
.
Location
==
CardLocation
.
SpellZone
)
return
true
;
if
(
Util
.
ChainContainsCard
(
destroyAllMonsterList
)
&&
Card
.
Location
==
CardLocation
.
MonsterZone
)
return
true
;
if
(
Duel
.
CurrentChain
.
Any
(
c
=>
c
.
Controller
==
1
&&
c
.
IsCode
(
destroyAllOpponentMonsterList
))
&&
Card
.
Location
==
CardLocation
.
MonsterZone
)
return
true
;
if
(
lightningStormOption
==
0
&&
Card
.
Location
==
CardLocation
.
MonsterZone
&&
Card
.
IsAttack
())
return
true
;
if
(
lightningStormOption
==
1
&&
Card
.
Location
==
CardLocation
.
SpellZone
)
return
true
;
// TODO: ChainContainsCard(id, player)
return
false
;
}
/// <summary>
/// Chain enemy activation or summon.
/// </summary>
protected
bool
DefaultTrap
()
{
if
(
DefaultCheckWhetherCardIsNegated
(
Card
))
return
false
;
return
(
Duel
.
LastChainPlayer
==
-
1
&&
Duel
.
LastSummonPlayer
!=
0
)
||
Duel
.
LastChainPlayer
==
1
;
}
/// <summary>
/// Activate when avail and no other our trap card in this chain or face-up.
/// </summary>
protected
bool
DefaultUniqueTrap
()
{
if
(
Util
.
HasChainedTrap
(
0
))
return
false
;
return
UniqueFaceupSpell
();
}
/// <summary>
/// Check no other our spell or trap card with same name face-up.
/// </summary>
protected
bool
UniqueFaceupSpell
()
{
return
!
Bot
.
GetSpells
().
Any
(
card
=>
card
.
IsCode
(
Card
.
Id
)
&&
card
.
IsFaceup
());
}
/// <summary>
/// Check no other our monster card with same name face-up.
/// </summary>
protected
bool
UniqueFaceupMonster
()
{
return
!
Bot
.
GetMonsters
().
Any
(
card
=>
card
.
IsCode
(
Card
.
Id
)
&&
card
.
IsFaceup
());
}
/// <summary>
/// Dumb way to avoid the bot chain in mess.
/// </summary>
protected
bool
DefaultDontChainMyself
()
{
if
(
Type
!=
ExecutorType
.
Activate
)
return
true
;
if
(
Executors
.
Any
(
exec
=>
exec
.
Type
==
Type
&&
exec
.
CardId
==
Card
.
Id
))
return
false
;
return
Duel
.
LastChainPlayer
!=
0
;
}
/// <summary>
/// Draw when we have lower LP, or destroy it. Can be overrided.
/// </summary>
protected
bool
DefaultChickenGame
()
{
if
(
Executors
.
Count
(
exec
=>
exec
.
Type
==
Type
&&
exec
.
CardId
==
Card
.
Id
)
>
1
)
return
false
;
if
(
Card
.
IsFacedown
())
return
true
;
if
(
Bot
.
LifePoints
<=
1000
)
return
false
;
if
(
Bot
.
LifePoints
<=
Enemy
.
LifePoints
&&
ActivateDescription
==
Util
.
GetStringId
(
_CardId
.
ChickenGame
,
0
))
return
true
;
return
true
;
if
(
Bot
.
LifePoints
>
Enemy
.
LifePoints
&&
ActivateDescription
==
Util
.
GetStringId
(
_CardId
.
ChickenGame
,
1
))
if
(
Bot
.
LifePoints
>
Enemy
.
LifePoints
&&
ActivateDescription
==
Util
.
GetStringId
(
_CardId
.
ChickenGame
,
1
))
return
true
;
return
true
;
...
@@ -1760,14 +1623,5 @@ namespace WindBot.Game.AI
...
@@ -1760,14 +1623,5 @@ namespace WindBot.Game.AI
}
}
return
false
;
return
false
;
}
}
protected
bool
DefaultGambleCard
()
{
int
[]
cardsname
=
new
[]
{
3280747
,
37812118
,
50470982
,
43061293
,
37313786
,
3493058
,
38299233
,
25173686
,
71625222
,
36562627
,
19162134
,
81172176
,
21598948
,
39537362
,
36378044
,
38143903
,
96012004
,
62784717
,
84290642
,
3549275
,
41139112
,
36708764
,
74137509
,
126218
,
93078761
,
76895648
,
22802010
,
83241722
,
84397023
,
31863912
,
39454112
,
59905358
,
5990062
,
9373534
,
58577036
};
if
(
Card
.
IsCode
(
cardsname
))
return
true
;
return
false
;
}
}
}
}
}
Game/GameAI.cs
View file @
078ad579
using
System.Linq
;
using
System.Linq
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Threading
;
using
WindBot.Game.AI
;
using
WindBot.Game.AI
;
using
YGOSharp.OCGWrapper.Enums
;
using
YGOSharp.OCGWrapper.Enums
;
using
System
;
using
System.Threading
;
namespace
WindBot.Game
namespace
WindBot.Game
{
{
...
@@ -50,6 +49,9 @@ namespace WindBot.Game
...
@@ -50,6 +49,9 @@ namespace WindBot.Game
public
void
OnDeckError
(
string
card
)
public
void
OnDeckError
(
string
card
)
{
{
_dialogs
.
SendDeckSorry
(
card
);
_dialogs
.
SendDeckSorry
(
card
);
Thread
.
Sleep
(
1000
);
_dialogs
.
SendSurrender
();
Game
.
Connection
.
Close
();
}
}
/// <summary>
/// <summary>
...
@@ -235,10 +237,10 @@ namespace WindBot.Game
...
@@ -235,10 +237,10 @@ namespace WindBot.Game
if
(
result
!=
null
)
if
(
result
!=
null
)
return
result
;
return
result
;
if
(
attackers
.
Count
==
0
)
//如果自己场上没有可以攻击的怪兽直接返回
if
(
attackers
.
Count
==
0
)
return
ToMainPhase2
();
return
ToMainPhase2
();
if
(
defenders
.
Count
==
0
)
//如果对方场上没有怪兽则直接攻击
if
(
defenders
.
Count
==
0
)
{
{
// Attack with the monster with the lowest attack first
// Attack with the monster with the lowest attack first
ClientCard
attacker
=
attackers
[
attackers
.
Count
-
1
];
ClientCard
attacker
=
attackers
[
attackers
.
Count
-
1
];
...
@@ -246,17 +248,17 @@ namespace WindBot.Game
...
@@ -246,17 +248,17 @@ namespace WindBot.Game
}
}
else
else
{
{
for
(
int
k
=
0
;
k
<
attackers
.
Count
;
++
k
)
//如果对方场上有怪兽
for
(
int
k
=
0
;
k
<
attackers
.
Count
;
++
k
)
{
{
ClientCard
attacker
=
attackers
[
k
];
ClientCard
attacker
=
attackers
[
k
];
attacker
.
IsLastAttacker
=
(
k
==
attackers
.
Count
-
1
);
attacker
.
IsLastAttacker
=
(
k
==
attackers
.
Count
-
1
);
result
=
Executor
.
OnSelectAttackTarget
(
attacker
,
defenders
);
//这个函数决定是否要攻击
result
=
Executor
.
OnSelectAttackTarget
(
attacker
,
defenders
);
if
(
result
!=
null
)
if
(
result
!=
null
)
return
result
;
return
result
;
}
}
}
}
if
(!
battle
.
CanMainPhaseTwo
)
//如果不能进战阶强制攻击
if
(!
battle
.
CanMainPhaseTwo
)
return
Attack
(
attackers
[
0
],
(
defenders
.
Count
==
0
)
?
null
:
defenders
[
0
]);
return
Attack
(
attackers
[
0
],
(
defenders
.
Count
==
0
)
?
null
:
defenders
[
0
]);
return
ToMainPhase2
();
return
ToMainPhase2
();
...
@@ -754,7 +756,7 @@ namespace WindBot.Game
...
@@ -754,7 +756,7 @@ namespace WindBot.Game
sorted
.
Sort
(
CardContainer
.
CompareCardAttack
);
sorted
.
Sort
(
CardContainer
.
CompareCardAttack
);
IList
<
ClientCard
>
selected
=
new
List
<
ClientCard
>();
IList
<
ClientCard
>
selected
=
new
List
<
ClientCard
>();
for
(
int
i
=
0
;
i
<
min
&&
i
<
sorted
.
Count
;
++
i
)
for
(
int
i
=
0
;
i
<
min
&&
i
<
sorted
.
Count
;
++
i
)
selected
.
Add
(
sorted
[
i
]);
selected
.
Add
(
sorted
[
i
]);
...
@@ -1172,15 +1174,10 @@ namespace WindBot.Game
...
@@ -1172,15 +1174,10 @@ namespace WindBot.Game
if
(!
Executor
.
OnPreActivate
(
card
))
if
(!
Executor
.
OnPreActivate
(
card
))
return
false
;
return
false
;
}
}
Func
<
bool
>
Func
=
()
=>
bool
result
=
card
!=
null
&&
exec
.
Type
==
type
&&
{
(
exec
.
CardId
==
-
1
||
exec
.
CardId
==
card
.
Id
)
&&
if
(
Executor
.
FuncFilters
.
ContainsKey
(
exec
.
Type
)
&&
Executor
.
FuncFilters
[
exec
.
Type
]
!=
null
(
exec
.
Func
==
null
||
exec
.
Func
());
&&
!
Executor
.
FuncFilters
[
exec
.
Type
]())
return
false
;
if
(
card
.
Id
!=
0
&&
type
==
ExecutorType
.
Activate
&&
result
)
return
exec
.
Func
==
null
||
exec
.
Func
();
};
bool
result
=
card
!=
null
&&
exec
.
Type
==
type
&&
(
exec
.
CardId
==
-
1
||
exec
.
CardId
==
card
.
Id
)
&&
Func
();
if
(
card
.
Id
!=
0
&&
type
==
ExecutorType
.
Activate
&&
result
)
{
{
int
count
=
card
.
IsDisabled
()
?
3
:
1
;
int
count
=
card
.
IsDisabled
()
?
3
:
1
;
if
(!
_activatedCards
.
ContainsKey
(
card
.
Id
))
if
(!
_activatedCards
.
ContainsKey
(
card
.
Id
))
...
...
xiaoye
@jwyxym
mentioned in commit
3359b06f
·
Dec 04, 2024
mentioned in commit
3359b06f
mentioned in commit 3359b06fa222796b0c6e0a081a6ae165da6c830d
Toggle commit list
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment