Compile-driven bulk-copy loop (tools/engine-port/m1_copy_loop.py) pulled the precise reference closure of the battle-core roots, stopping at the classify god-object/View-VFX-UI boundary. 782 files; no re-explosion (M0 had estimated ~order 1000). Residual frontier = 52 shim-classified + 80 external (Unity/BCL) types to author next.
2654 lines
72 KiB
C#
2654 lines
72 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
|
|
namespace Wizard;
|
|
|
|
public class AIVirtualCard
|
|
{
|
|
public class AIVirtualBanishInfo
|
|
{
|
|
public int Turn { get; private set; }
|
|
|
|
public bool IsCardOwnerTurn { get; private set; }
|
|
|
|
public BattleCardBase.BanishInfo.BanishPlace Place { get; private set; }
|
|
|
|
public AIVirtualBanishInfo(int turn, bool isCardOwnerTurn, BattleCardBase.BanishInfo.BanishPlace place)
|
|
{
|
|
Turn = turn;
|
|
IsCardOwnerTurn = isCardOwnerTurn;
|
|
Place = place;
|
|
}
|
|
}
|
|
|
|
protected AIVirtualField _field;
|
|
|
|
public bool IsFirstTurn;
|
|
|
|
public int BaseCost;
|
|
|
|
public int Cost;
|
|
|
|
public int RealCost;
|
|
|
|
public int PlayedCost = -1;
|
|
|
|
public List<int> EnhanceCostList;
|
|
|
|
public List<AIAccelerateInformation> AccelerateCostList;
|
|
|
|
public List<AICrystalizeInformation> CrystalizeCostList;
|
|
|
|
public List<AIChoiceTransformCostInformation> ChoiceTransformCostList;
|
|
|
|
public int LastHealAmount;
|
|
|
|
public int AttackableCount;
|
|
|
|
public bool IsSummonDrunkenness;
|
|
|
|
private bool IsDebuffCantEvolve;
|
|
|
|
public bool IsCantAttackAll;
|
|
|
|
public bool IsSkillCantAttackClass;
|
|
|
|
public bool IsSkillCantAttackUnit;
|
|
|
|
public bool IsSkillCantAtkUnitNotHasGuard;
|
|
|
|
private List<AICannotAttackInformation> _cannotAttackInfoList;
|
|
|
|
private bool _isCantUnderAttack;
|
|
|
|
public bool IsSkillCantUnderAnyAttack;
|
|
|
|
public bool IsUseEvo;
|
|
|
|
public bool IsGuard;
|
|
|
|
public bool IsIgnoreGuard;
|
|
|
|
public bool IsSkillLost;
|
|
|
|
public bool IsSelfTurn;
|
|
|
|
public bool IsNotAttackYet;
|
|
|
|
public bool IsMinimumBreakBonus;
|
|
|
|
public bool IsRobbedLastword;
|
|
|
|
public bool IsNotConsumeEp;
|
|
|
|
public bool IsSkillSummoned;
|
|
|
|
public bool HasAnySkill;
|
|
|
|
public bool HasSkillNecromance;
|
|
|
|
public bool IsPlayer;
|
|
|
|
public bool IsForceTargeting;
|
|
|
|
public bool IsUnbanishable;
|
|
|
|
public bool IsMetamorphosed;
|
|
|
|
private int UntouchableCount;
|
|
|
|
public AIBarrierInfoCollection BarrierInfoCollection;
|
|
|
|
public bool IsIndestructible;
|
|
|
|
public bool IsIndependent;
|
|
|
|
private int _destroyByBanishCount;
|
|
|
|
private int _bounceByBanishCount;
|
|
|
|
private int _banishByDestroyCount;
|
|
|
|
public int AttackByLifeCount;
|
|
|
|
public bool IsSneak;
|
|
|
|
private List<AIPlayTag> _giveSneakTagList;
|
|
|
|
public bool IsKiller;
|
|
|
|
public bool IsDrain;
|
|
|
|
public bool IsRush;
|
|
|
|
public bool IsQuick;
|
|
|
|
public bool IsDestroyWhenAttack;
|
|
|
|
public bool HasSpellboost;
|
|
|
|
public int SpellboostCount;
|
|
|
|
public int RealSpellboostCount;
|
|
|
|
private int _originalWhiteRitualCount;
|
|
|
|
public bool IsStackWhiteRitual;
|
|
|
|
public int TempAtkBuff;
|
|
|
|
public int TempLifeBuff;
|
|
|
|
public bool HasAfterAttackHeal;
|
|
|
|
public bool IsRecoveredAttackableCount;
|
|
|
|
public bool IsAmulet;
|
|
|
|
public bool IsCountdownAmulet;
|
|
|
|
public int ChantCount;
|
|
|
|
public bool IsSpell;
|
|
|
|
public bool IsUnit;
|
|
|
|
public bool IsLeader;
|
|
|
|
protected bool _isCompletedRemove;
|
|
|
|
public bool IsDead;
|
|
|
|
private AIHandPlayEstimator _handPlayEstimator;
|
|
|
|
protected List<CardBasePrm.TribeType> _tribeList;
|
|
|
|
public readonly AIVirtualAttackInfo AttackLeaderSituation;
|
|
|
|
public int GetOnCardId;
|
|
|
|
public AIVirtualCard GetOffCard;
|
|
|
|
public AIVirtualCard BeforeTransformedCardForSimulation;
|
|
|
|
public List<string> PermanentAITribeList;
|
|
|
|
public int ReferringSelfCount;
|
|
|
|
protected readonly ulong[] PRIME_NUMBERS_FOR_CLAN = new ulong[12]
|
|
{
|
|
282143uL, 282157uL, 282167uL, 282221uL, 282229uL, 282239uL, 282241uL, 282253uL, 282281uL, 282287uL,
|
|
282299uL, 282307uL
|
|
};
|
|
|
|
protected readonly ulong[] PRIME_NUMBERS_FOR_TRIBE = new ulong[13]
|
|
{
|
|
47521uL, 47527uL, 47533uL, 47543uL, 47563uL, 47569uL, 47581uL, 47591uL, 47599uL, 47609uL,
|
|
47623uL, 47629uL, 47639uL
|
|
};
|
|
|
|
public AIVirtualField SelfField => _field;
|
|
|
|
public AICardData AIData { get; private set; }
|
|
|
|
public BattlePlayerBase SelfBattlePlayer { get; protected set; }
|
|
|
|
public int BaseId
|
|
{
|
|
get
|
|
{
|
|
return CardParameter.BaseId;
|
|
}
|
|
protected set
|
|
{
|
|
CardParameter.BaseId = value;
|
|
}
|
|
}
|
|
|
|
public int CardIndex { get; protected set; }
|
|
|
|
public string CardName => CardParameter.CardName;
|
|
|
|
public int EvolutionAttack => CardParameter.Attack + CardParameter.EvoAttackPlus;
|
|
|
|
public int EvolutionLife => CardParameter.Life + CardParameter.EvoLifePlus;
|
|
|
|
public CardBasePrm.ClanType Clan { get; protected set; }
|
|
|
|
public bool IsEvolution { get; private set; }
|
|
|
|
public bool IsPreviousTurnAttacked { get; private set; }
|
|
|
|
public bool IsOnField { get; protected set; }
|
|
|
|
public bool IsInHand { get; protected set; }
|
|
|
|
public BattleCardBase BaseCard { get; protected set; }
|
|
|
|
public SkillCollectionBase BattleSkills { get; protected set; }
|
|
|
|
public List<string> BattleSkillHashList { get; protected set; }
|
|
|
|
public AIVirtualCardParameter BaseParameter { get; private set; }
|
|
|
|
public AIVirtualCardParameter OtherEvolveParameter { get; private set; }
|
|
|
|
public AIVirtualCardParameter CardParameter
|
|
{
|
|
get
|
|
{
|
|
if (OtherEvolveParameter != null)
|
|
{
|
|
return OtherEvolveParameter;
|
|
}
|
|
return BaseParameter;
|
|
}
|
|
}
|
|
|
|
public int Life
|
|
{
|
|
get
|
|
{
|
|
return CardParameter.Life;
|
|
}
|
|
set
|
|
{
|
|
CardParameter.Life = value;
|
|
}
|
|
}
|
|
|
|
public int MaxLife
|
|
{
|
|
get
|
|
{
|
|
return CardParameter.MaxLife;
|
|
}
|
|
set
|
|
{
|
|
CardParameter.MaxLife = value;
|
|
}
|
|
}
|
|
|
|
public int DefLife
|
|
{
|
|
get
|
|
{
|
|
return CardParameter.DefLife;
|
|
}
|
|
set
|
|
{
|
|
CardParameter.DefLife = value;
|
|
}
|
|
}
|
|
|
|
public int LastLife
|
|
{
|
|
get
|
|
{
|
|
return CardParameter.LastLife;
|
|
}
|
|
set
|
|
{
|
|
CardParameter.LastLife = value;
|
|
}
|
|
}
|
|
|
|
public int Attack
|
|
{
|
|
get
|
|
{
|
|
return CardParameter.Attack;
|
|
}
|
|
set
|
|
{
|
|
CardParameter.Attack = value;
|
|
}
|
|
}
|
|
|
|
public int MaxAttackableCount
|
|
{
|
|
get
|
|
{
|
|
return CardParameter.MaxAttackableCount;
|
|
}
|
|
set
|
|
{
|
|
CardParameter.MaxAttackableCount = value;
|
|
}
|
|
}
|
|
|
|
public int DefaultLife
|
|
{
|
|
get
|
|
{
|
|
return CardParameter.DefaultLife;
|
|
}
|
|
set
|
|
{
|
|
CardParameter.DefaultLife = value;
|
|
}
|
|
}
|
|
|
|
public int DefaultAttack
|
|
{
|
|
get
|
|
{
|
|
return CardParameter.DefaultAttack;
|
|
}
|
|
set
|
|
{
|
|
CardParameter.DefaultAttack = value;
|
|
}
|
|
}
|
|
|
|
public int DefaultMaxAttackableCount
|
|
{
|
|
get
|
|
{
|
|
return CardParameter.DefaultMaxAttackableCount;
|
|
}
|
|
set
|
|
{
|
|
CardParameter.DefaultMaxAttackableCount = value;
|
|
}
|
|
}
|
|
|
|
public bool IsAttacked => AttackableCount < MaxAttackableCount;
|
|
|
|
public bool IsUntouchable => UntouchableCount > 0;
|
|
|
|
public int DestroyedTurn { get; protected set; }
|
|
|
|
public int EvoAttackPlus
|
|
{
|
|
get
|
|
{
|
|
return CardParameter.EvoAttackPlus;
|
|
}
|
|
private set
|
|
{
|
|
CardParameter.EvoAttackPlus = value;
|
|
}
|
|
}
|
|
|
|
public int EvoLifePlus
|
|
{
|
|
get
|
|
{
|
|
return CardParameter.EvoLifePlus;
|
|
}
|
|
private set
|
|
{
|
|
CardParameter.EvoLifePlus = value;
|
|
}
|
|
}
|
|
|
|
public int BuffCount { get; private set; }
|
|
|
|
public AIBuffRecorderCollection BuffRecorderCollection { get; private set; }
|
|
|
|
public int SelfTurnDamagedCount { get; private set; }
|
|
|
|
public int OpponentTurnDamagedCount { get; private set; }
|
|
|
|
public int HealCount { get; private set; }
|
|
|
|
public bool IsAllShield
|
|
{
|
|
get
|
|
{
|
|
if (BarrierInfoCollection == null)
|
|
{
|
|
return false;
|
|
}
|
|
return BarrierInfoCollection.HasShieldAll;
|
|
}
|
|
}
|
|
|
|
public bool IsDestroyByBanish => _destroyByBanishCount > 0;
|
|
|
|
public bool IsBounceByBanish => _bounceByBanishCount > 0;
|
|
|
|
public bool IsBanishByDestroy => _banishByDestroyCount > 0;
|
|
|
|
public bool IsAttackByLife => AttackByLifeCount > 0;
|
|
|
|
public bool IsLastword { get; private set; }
|
|
|
|
public float Value { get; private set; }
|
|
|
|
public float DefaultValue { get; private set; }
|
|
|
|
public int WhiteRitualCount { get; protected set; }
|
|
|
|
public bool IsAlly { get; protected set; }
|
|
|
|
public bool DeadTurn { get; set; }
|
|
|
|
public AITagCollectionContainer TagCollectionContainer { get; protected set; }
|
|
|
|
public List<int> ChildrenIndexList { get; private set; }
|
|
|
|
public bool HasUnionBurst { get; private set; }
|
|
|
|
public int UnionBurstCount { get; private set; }
|
|
|
|
public bool HasSkyboundArt { get; private set; }
|
|
|
|
public int SkyboundArtCount { get; private set; }
|
|
|
|
public bool HasSuperSkyboundArt { get; private set; }
|
|
|
|
public int SuperSkyboundArtCount { get; private set; }
|
|
|
|
public bool IsFusionCard => TagCollectionContainer.HasTag(AIPlayTagType.Fusion);
|
|
|
|
public bool IsFusionable { get; private set; }
|
|
|
|
public AIVirtualFusionIngredientsInfo FusionIngredients { get; protected set; }
|
|
|
|
public BeforeTransformVirtualCard BeforeTransformCard { get; private set; }
|
|
|
|
public bool IsGetOn => GetOnCardId > 0;
|
|
|
|
public bool CantBeFocusedSkill
|
|
{
|
|
get
|
|
{
|
|
if (!IsSneak)
|
|
{
|
|
return IsUntouchable;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public AIVirtualBanishInfo BanishedInfo { get; private set; }
|
|
|
|
public bool IsTribe(CardBasePrm.TribeType tribe)
|
|
{
|
|
if (_tribeList == null)
|
|
{
|
|
return false;
|
|
}
|
|
for (int i = 0; i < _tribeList.Count; i++)
|
|
{
|
|
if (_tribeList[i] == tribe)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool HasAnyTribe()
|
|
{
|
|
if (_tribeList == null)
|
|
{
|
|
return false;
|
|
}
|
|
for (int i = 0; i < _tribeList.Count; i++)
|
|
{
|
|
if (_tribeList[i] != CardBasePrm.TribeType.ALL)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public AIVirtualCard()
|
|
{
|
|
}
|
|
|
|
public AIVirtualCard(BattleCardBase card, AIVirtualField field)
|
|
{
|
|
_field = field;
|
|
IsAlly = _field.AI.IsAllyCard(card);
|
|
TagCollectionContainer = new AITagCollectionContainer();
|
|
BarrierInfoCollection = new AIBarrierInfoCollection();
|
|
InitializeFromBattleCardBase(card);
|
|
InitializeAIParameter();
|
|
if (IsAlly && !IsLeader)
|
|
{
|
|
AttackLeaderSituation = new AIVirtualAttackInfo(this, _field.EnemyClass);
|
|
}
|
|
else
|
|
{
|
|
AttackLeaderSituation = null;
|
|
}
|
|
}
|
|
|
|
public AIVirtualCard(AIVirtualCard virtualCard, AIVirtualField field)
|
|
{
|
|
_field = field;
|
|
SelfBattlePlayer = virtualCard.SelfBattlePlayer;
|
|
AIData = virtualCard.AIData;
|
|
IsAlly = virtualCard.IsAlly;
|
|
BaseCost = virtualCard.BaseCost;
|
|
Cost = virtualCard.Cost;
|
|
RealCost = virtualCard.RealCost;
|
|
PlayedCost = virtualCard.PlayedCost;
|
|
IsDead = virtualCard.IsDead;
|
|
_isCompletedRemove = virtualCard._isCompletedRemove;
|
|
ChildrenIndexList = virtualCard.ChildrenIndexList;
|
|
IsPlayer = virtualCard.IsPlayer;
|
|
BaseCard = virtualCard.BaseCard;
|
|
CardIndex = virtualCard.CardIndex;
|
|
BattleSkills = virtualCard.BattleSkills;
|
|
BattleSkillHashList = virtualCard.BattleSkillHashList;
|
|
BaseParameter = virtualCard.BaseParameter.Clone();
|
|
OtherEvolveParameter = ((virtualCard.OtherEvolveParameter != null) ? virtualCard.OtherEvolveParameter.Clone() : null);
|
|
IsSpell = virtualCard.IsSpell;
|
|
IsUnit = virtualCard.IsUnit;
|
|
IsLeader = virtualCard.IsLeader;
|
|
Clan = virtualCard.Clan;
|
|
AttackableCount = virtualCard.AttackableCount;
|
|
IsCantAttackAll = virtualCard.IsCantAttackAll;
|
|
IsFirstTurn = virtualCard.IsFirstTurn;
|
|
IsSummonDrunkenness = virtualCard.IsSummonDrunkenness;
|
|
IsSkillCantAttackClass = virtualCard.IsSkillCantAttackClass;
|
|
IsSkillCantAttackUnit = virtualCard.IsSkillCantAttackUnit;
|
|
_cannotAttackInfoList = AIParamQuery.CloneList(virtualCard._cannotAttackInfoList);
|
|
_isCantUnderAttack = virtualCard._isCantUnderAttack;
|
|
IsSkillCantAtkUnitNotHasGuard = virtualCard.IsSkillCantAtkUnitNotHasGuard;
|
|
IsGuard = virtualCard.IsGuard;
|
|
IsSkillCantUnderAnyAttack = virtualCard.IsSkillCantUnderAnyAttack;
|
|
IsIgnoreGuard = virtualCard.IsIgnoreGuard;
|
|
IsSkillLost = virtualCard.IsSkillLost;
|
|
IsSelfTurn = virtualCard.IsSelfTurn;
|
|
IsNotAttackYet = virtualCard.IsNotAttackYet;
|
|
IsMinimumBreakBonus = virtualCard.IsMinimumBreakBonus;
|
|
IsRobbedLastword = virtualCard.IsRobbedLastword;
|
|
IsNotConsumeEp = virtualCard.IsNotConsumeEp;
|
|
IsSkillSummoned = virtualCard.IsSkillSummoned;
|
|
HasAnySkill = virtualCard.HasAnySkill;
|
|
IsOnField = virtualCard.IsOnField;
|
|
IsInHand = virtualCard.IsInHand;
|
|
IsUseEvo = virtualCard.IsUseEvo;
|
|
IsEvolution = virtualCard.IsEvolution;
|
|
IsPreviousTurnAttacked = virtualCard.IsPreviousTurnAttacked;
|
|
IsIndestructible = virtualCard.IsIndestructible;
|
|
IsIndependent = virtualCard.IsIndependent;
|
|
IsMetamorphosed = virtualCard.IsMetamorphosed;
|
|
IsLastword = virtualCard.IsLastword;
|
|
IsSneak = virtualCard.IsSneak;
|
|
_giveSneakTagList = AIParamQuery.CloneList(virtualCard._giveSneakTagList);
|
|
IsKiller = virtualCard.IsKiller;
|
|
IsDrain = virtualCard.IsDrain;
|
|
IsRush = virtualCard.IsRush;
|
|
IsQuick = virtualCard.IsQuick;
|
|
IsDestroyWhenAttack = virtualCard.IsDestroyWhenAttack;
|
|
IsRecoveredAttackableCount = virtualCard.IsRecoveredAttackableCount;
|
|
IsForceTargeting = virtualCard.IsForceTargeting;
|
|
IsUnbanishable = virtualCard.IsUnbanishable;
|
|
UntouchableCount = virtualCard.UntouchableCount;
|
|
IsDebuffCantEvolve = virtualCard.IsDebuffCantEvolve;
|
|
_destroyByBanishCount = virtualCard._destroyByBanishCount;
|
|
_bounceByBanishCount = virtualCard._bounceByBanishCount;
|
|
_banishByDestroyCount = virtualCard._banishByDestroyCount;
|
|
HasSpellboost = virtualCard.HasSpellboost;
|
|
SpellboostCount = virtualCard.SpellboostCount;
|
|
RealSpellboostCount = virtualCard.RealSpellboostCount;
|
|
WhiteRitualCount = virtualCard.WhiteRitualCount;
|
|
_originalWhiteRitualCount = virtualCard._originalWhiteRitualCount;
|
|
IsStackWhiteRitual = virtualCard.IsStackWhiteRitual;
|
|
AttackByLifeCount = virtualCard.AttackByLifeCount;
|
|
TempAtkBuff = virtualCard.TempAtkBuff;
|
|
TempLifeBuff = virtualCard.TempLifeBuff;
|
|
BuffCount = virtualCard.BuffCount;
|
|
if (virtualCard.BuffRecorderCollection != null)
|
|
{
|
|
BuffRecorderCollection = virtualCard.BuffRecorderCollection.Clone();
|
|
}
|
|
SelfTurnDamagedCount = virtualCard.SelfTurnDamagedCount;
|
|
OpponentTurnDamagedCount = virtualCard.OpponentTurnDamagedCount;
|
|
HealCount = virtualCard.HealCount;
|
|
HasAfterAttackHeal = virtualCard.HasAfterAttackHeal;
|
|
DestroyedTurn = virtualCard.DestroyedTurn;
|
|
ReferringSelfCount = virtualCard.ReferringSelfCount;
|
|
TagCollectionContainer = new AITagCollectionContainer(virtualCard.TagCollectionContainer, this);
|
|
BarrierInfoCollection = virtualCard.BarrierInfoCollection.Clone();
|
|
IsAmulet = virtualCard.IsAmulet;
|
|
IsCountdownAmulet = virtualCard.IsCountdownAmulet;
|
|
ChantCount = virtualCard.ChantCount;
|
|
Value = virtualCard.Value;
|
|
DefaultValue = virtualCard.DefaultValue;
|
|
if (virtualCard._tribeList != null)
|
|
{
|
|
_tribeList = new List<CardBasePrm.TribeType>(virtualCard._tribeList);
|
|
}
|
|
IsFusionable = virtualCard.IsFusionable;
|
|
if (virtualCard.FusionIngredients != null)
|
|
{
|
|
FusionIngredients = new AIVirtualFusionIngredientsInfo(virtualCard.FusionIngredients);
|
|
}
|
|
HasUnionBurst = virtualCard.HasUnionBurst;
|
|
UnionBurstCount = virtualCard.UnionBurstCount;
|
|
HasSkyboundArt = virtualCard.HasSkyboundArt;
|
|
SkyboundArtCount = virtualCard.SkyboundArtCount;
|
|
HasSuperSkyboundArt = virtualCard.HasSuperSkyboundArt;
|
|
SuperSkyboundArtCount = virtualCard.SuperSkyboundArtCount;
|
|
GetOnCardId = virtualCard.GetOnCardId;
|
|
GetOffCard = virtualCard.GetOffCard;
|
|
BeforeTransformCard = null;
|
|
if (virtualCard.BeforeTransformCard != null)
|
|
{
|
|
BeforeTransformCard = new BeforeTransformVirtualCard(virtualCard.BeforeTransformCard, _field);
|
|
}
|
|
if (IsAlly && !IsLeader)
|
|
{
|
|
AttackLeaderSituation = new AIVirtualAttackInfo(this, _field.EnemyClass);
|
|
}
|
|
else
|
|
{
|
|
AttackLeaderSituation = null;
|
|
}
|
|
BanishedInfo = virtualCard.BanishedInfo;
|
|
BeforeTransformedCardForSimulation = virtualCard.BeforeTransformedCardForSimulation;
|
|
PermanentAITribeList = virtualCard.PermanentAITribeList;
|
|
}
|
|
|
|
public AIVirtualCard(AIVirtualField field, AIVirtualCardParameter baseParameter, AIVirtualCard evalInstantAttackOwner, bool isEvalRush)
|
|
{
|
|
_field = field;
|
|
BaseParameter = baseParameter;
|
|
OtherEvolveParameter = null;
|
|
IsAlly = evalInstantAttackOwner.IsAlly;
|
|
IsPlayer = evalInstantAttackOwner.IsPlayer;
|
|
SelfBattlePlayer = evalInstantAttackOwner.SelfBattlePlayer;
|
|
AIData = evalInstantAttackOwner.AIData;
|
|
BaseCost = 0;
|
|
Cost = 0;
|
|
RealCost = 0;
|
|
PlayedCost = 0;
|
|
ChildrenIndexList = null;
|
|
BaseCard = evalInstantAttackOwner.BaseCard;
|
|
CardIndex = evalInstantAttackOwner.CardIndex;
|
|
BattleSkills = evalInstantAttackOwner.BattleSkills;
|
|
BattleSkillHashList = evalInstantAttackOwner.BattleSkillHashList;
|
|
IsUnit = true;
|
|
Clan = evalInstantAttackOwner.Clan;
|
|
AttackableCount = BaseParameter.MaxAttackableCount;
|
|
IsFirstTurn = true;
|
|
IsSummonDrunkenness = false;
|
|
IsSelfTurn = evalInstantAttackOwner.IsSelfTurn;
|
|
IsNotAttackYet = true;
|
|
IsMinimumBreakBonus = evalInstantAttackOwner.IsMinimumBreakBonus;
|
|
HasAnySkill = evalInstantAttackOwner.HasAnySkill;
|
|
IsOnField = true;
|
|
IsRush = isEvalRush;
|
|
IsQuick = !isEvalRush;
|
|
_destroyByBanishCount = 0;
|
|
_bounceByBanishCount = 0;
|
|
_banishByDestroyCount = 0;
|
|
SpellboostCount = 0;
|
|
RealSpellboostCount = 0;
|
|
WhiteRitualCount = 0;
|
|
_originalWhiteRitualCount = 0;
|
|
AttackByLifeCount = 0;
|
|
TempAtkBuff = 0;
|
|
TempLifeBuff = 0;
|
|
BuffCount = 0;
|
|
SelfTurnDamagedCount = 0;
|
|
OpponentTurnDamagedCount = 0;
|
|
HealCount = 0;
|
|
DestroyedTurn = evalInstantAttackOwner.DestroyedTurn;
|
|
ReferringSelfCount = 0;
|
|
ChantCount = 0;
|
|
UnionBurstCount = 0;
|
|
SkyboundArtCount = 0;
|
|
SuperSkyboundArtCount = 0;
|
|
TagCollectionContainer = new AITagCollectionContainer(evalInstantAttackOwner.TagCollectionContainer, this);
|
|
BarrierInfoCollection = new AIBarrierInfoCollection();
|
|
BuffRecorderCollection = null;
|
|
if (evalInstantAttackOwner._tribeList != null)
|
|
{
|
|
_tribeList = new List<CardBasePrm.TribeType>(evalInstantAttackOwner._tribeList);
|
|
}
|
|
if (IsAlly && !IsLeader)
|
|
{
|
|
AttackLeaderSituation = new AIVirtualAttackInfo(this, _field.EnemyClass);
|
|
}
|
|
else
|
|
{
|
|
AttackLeaderSituation = null;
|
|
}
|
|
}
|
|
|
|
protected virtual void InitializeFromBattleCardBase(BattleCardBase origin)
|
|
{
|
|
InitializeFromBattleCardBaseBasic(origin);
|
|
SelfBattlePlayer = origin.SelfBattlePlayer;
|
|
Value = 0f;
|
|
DefaultValue = 0f;
|
|
CardIndex = origin.Index;
|
|
IsDead = origin.IsDead;
|
|
IsPlayer = origin.IsPlayer;
|
|
BattleSkills = origin.Skills;
|
|
BattleSkillHashList = CardSkillHashUtility.GetSingleSkillHashStringList(BattleSkills);
|
|
IsSkillSummoned = origin.SelfBattlePlayer.SkillSummonedCards != null && origin.SelfBattlePlayer.SkillSummonedCards.Any((BattleCardBase c) => c.Index == origin.Index);
|
|
ISkillApplyInformation skillApplyInformation = origin.SkillApplyInformation;
|
|
Cost = origin.Cost;
|
|
RealCost = origin.Cost;
|
|
PlayedCost = origin.PlayedCost;
|
|
if (origin.Tribe != null && origin.Tribe.Count > 0)
|
|
{
|
|
for (int num = 0; num < origin.Tribe.Count; num++)
|
|
{
|
|
AppendTribe(origin.Tribe[num]);
|
|
}
|
|
}
|
|
IsOnField = origin.IsInplay;
|
|
IsInHand = origin.IsInHand;
|
|
IsSelfTurn = origin.IsSelfTurn;
|
|
IsFirstTurn = origin.IsFirstTurn;
|
|
IsSummonDrunkenness = origin.IsSummonDrunkenness;
|
|
IsCantAttackAll = origin.IsCantAttack;
|
|
IsSkillCantAttackClass = skillApplyInformation.IsSkillCantAtkClass;
|
|
IsSkillCantAttackUnit = skillApplyInformation.IsSkillCantAtkUnit;
|
|
IsSkillCantAtkUnitNotHasGuard = skillApplyInformation.IsSkillCantAtkUnitNotHasGuard;
|
|
IsSkillCantUnderAnyAttack = skillApplyInformation.NotBeAttackedInfoList.Count > 0;
|
|
_isCantUnderAttack = skillApplyInformation.IsSneak || IsSkillCantUnderAnyAttack;
|
|
IsIgnoreGuard = skillApplyInformation.IsIgnoreGuard;
|
|
IsNotConsumeEp = origin.SelfBattlePlayer.CheckNotConsumeEpCard(origin);
|
|
IsEvolution = IsUnit && origin.IsEvolution;
|
|
IsPreviousTurnAttacked = IsUnit && origin.IsPreviousTurnAttacked;
|
|
HasAnySkill = origin.HasAnySkill;
|
|
HasSkillNecromance = origin.HasSkillNecromance;
|
|
IsSkillLost = origin.IsSkillLost;
|
|
IsLastword = origin.Skills._skillTimingInfo.IsWhenDestroy;
|
|
IsSneak = IsUnit && skillApplyInformation.IsSneak;
|
|
IsKiller = IsUnit && skillApplyInformation.IsKiller;
|
|
IsDrain = IsUnit && skillApplyInformation.IsDrain;
|
|
IsRush = IsUnit && skillApplyInformation.IsRush;
|
|
IsQuick = skillApplyInformation.IsQuick;
|
|
IsGuard = IsUnit && skillApplyInformation.IsGuard;
|
|
IsIndestructible = skillApplyInformation.IndestructibleCount > 0;
|
|
IsIndependent = skillApplyInformation.IndependentCount > 0;
|
|
DestroyedTurn = origin.DestroyedTurn;
|
|
UntouchableCount = skillApplyInformation.UntouchableCount;
|
|
IsForceTargeting = skillApplyInformation.IsForceSkillTarget;
|
|
IsUnbanishable = false;
|
|
HasSpellboost = origin.HasSpellCharge;
|
|
SpellboostCount = origin.SpellChargeCount;
|
|
RealSpellboostCount = origin.SpellChargeCount;
|
|
WhiteRitualCount = (IsAmulet ? skillApplyInformation.WhiteRitualCount : 0);
|
|
_originalWhiteRitualCount = WhiteRitualCount;
|
|
IsStackWhiteRitual = origin.HasSkillStackWhiteRitual;
|
|
IsDebuffCantEvolve = skillApplyInformation.CantEvolutionList != null && skillApplyInformation.CantEvolutionList.Any((int f) => (f & Skill_cant_evolution.BIT_FLAG_EPUSE) != 0);
|
|
_banishByDestroyCount = skillApplyInformation.BanishByDestroyCount;
|
|
_destroyByBanishCount = skillApplyInformation.DestroyByBanishCount;
|
|
_bounceByBanishCount = skillApplyInformation.ReturnByBanishCount;
|
|
if (IsCountdownAmulet)
|
|
{
|
|
ChantCount = ((ChantFieldBattleCard)origin).ChantCount;
|
|
}
|
|
AttackableCount = (IsUnit ? origin.AttackableCount : 0);
|
|
BuffCount = (IsUnit ? skillApplyInformation.BuffCount : 0);
|
|
BuffRecorderCollection = (IsUnit ? new AIBuffRecorderCollection(skillApplyInformation.TurnBuffCountList) : null);
|
|
SelfTurnDamagedCount = ((!IsAmulet) ? origin.DamagedCounter.SelfTurnDamage : 0);
|
|
OpponentTurnDamagedCount = ((!IsAmulet) ? origin.DamagedCounter.OpponentTurnDamage : 0);
|
|
HealCount = ((!IsAmulet && skillApplyInformation.HealList != null) ? skillApplyInformation.HealList.Count : 0);
|
|
HasUnionBurst = origin.HasUnionBurst;
|
|
if (HasUnionBurst)
|
|
{
|
|
UnionBurstCount = skillApplyInformation.UnionBurstCount;
|
|
}
|
|
HasSkyboundArt = origin.HasSkyboundArt;
|
|
if (HasSkyboundArt)
|
|
{
|
|
SkyboundArtCount = skillApplyInformation.SkyboundArtCount;
|
|
}
|
|
HasSuperSkyboundArt = origin.HasSuperSkyboundArt;
|
|
if (HasSuperSkyboundArt)
|
|
{
|
|
SuperSkyboundArtCount = skillApplyInformation.SuperSkyboundArtCount;
|
|
}
|
|
BeforeTransformCard = null;
|
|
BattleCardBase.TransformInformation transformInfo = origin.TransformInfo;
|
|
if (transformInfo.Type != BattleCardBase.TransformType.Metamorphose && transformInfo.OriginalCard != null)
|
|
{
|
|
BeforeTransformCard = new BeforeTransformVirtualCard(transformInfo.OriginalCard, _field);
|
|
}
|
|
if (skillApplyInformation.GetOnCards != null && skillApplyInformation.GetOnCards.Count > 0)
|
|
{
|
|
GetOnCardId = skillApplyInformation.GetOnCards[0].BaseParameter.BaseCardId;
|
|
}
|
|
if (origin.GetOffCards != null && origin.GetOffCards.Count > 0)
|
|
{
|
|
GetOffCard = new AIVirtualCard(origin.GetOffCards[0], _field);
|
|
}
|
|
IsFusionable = origin.IsFusionable;
|
|
FusionIngredients = new AIVirtualFusionIngredientsInfo();
|
|
if (skillApplyInformation.FusionIngredients != null && skillApplyInformation.FusionIngredients.Count > 0)
|
|
{
|
|
FusionIngredients.CopyFusionIngredientsFromBattleCard(skillApplyInformation.FusionIngredients, _field);
|
|
}
|
|
ConvertBaseBanishInfo(origin.BanishedInfo);
|
|
BeforeTransformedCardForSimulation = null;
|
|
}
|
|
|
|
protected void InitializeFromBattleCardBaseBasic(BattleCardBase origin)
|
|
{
|
|
BaseCard = origin;
|
|
BaseCost = origin.BaseCost;
|
|
Clan = origin.Clan;
|
|
IsUnit = origin.IsUnit;
|
|
IsSpell = origin.IsSpell;
|
|
IsAmulet = origin.IsField;
|
|
IsCountdownAmulet = origin.IsChantField;
|
|
IsLeader = origin.IsClass;
|
|
IsRecoveredAttackableCount = false;
|
|
BaseParameter = new AIVirtualCardParameter(origin);
|
|
OtherEvolveParameter = null;
|
|
PermanentAITribeList = _field.GetReferenceTribe(BaseId);
|
|
int referenceId = _field.GetReferenceId(origin.CardId);
|
|
if (referenceId > 0)
|
|
{
|
|
BaseId = referenceId;
|
|
}
|
|
}
|
|
|
|
protected virtual void InitializeAIParameter()
|
|
{
|
|
IsUseEvo = false;
|
|
IsNotAttackYet = !IsAmulet;
|
|
IsMinimumBreakBonus = false;
|
|
IsRobbedLastword = false;
|
|
IsDestroyWhenAttack = false;
|
|
HasAfterAttackHeal = false;
|
|
IsMetamorphosed = false;
|
|
Value = 0f;
|
|
DefaultValue = 0f;
|
|
AttackByLifeCount = 0;
|
|
TempAtkBuff = 0;
|
|
TempLifeBuff = 0;
|
|
ChildrenIndexList = null;
|
|
}
|
|
|
|
public void InitializeEnemyHandParameter()
|
|
{
|
|
IsAlly = false;
|
|
IsInHand = true;
|
|
IsOnField = false;
|
|
}
|
|
|
|
private void InitializeFollowerTags(AIParamQuery query)
|
|
{
|
|
BattleCardBase baseCard = BaseCard;
|
|
if (IsSkillLost)
|
|
{
|
|
IsRobbedLastword = false;
|
|
IsDestroyWhenAttack = false;
|
|
HasAfterAttackHeal = false;
|
|
}
|
|
else
|
|
{
|
|
IsRobbedLastword = query.IsRobbedLastword(baseCard);
|
|
IsDestroyWhenAttack = query.IsDestroyBeforeAttack(baseCard);
|
|
TagCollectionContainer.InitTags(this, query);
|
|
HasAfterAttackHeal = TagCollectionContainer.HasTag(AIPlayTagType.AfterAttackHeal);
|
|
}
|
|
}
|
|
|
|
private void InitializeAmuletTags(AIParamQuery query)
|
|
{
|
|
if (!IsSkillLost)
|
|
{
|
|
TagCollectionContainer.InitTags(this, query);
|
|
}
|
|
}
|
|
|
|
public virtual void InitializeTags(AIParamQuery query, AIAttachedTagCollection attachedTagCollection, AIRemovedTagCollection removedTagCollection)
|
|
{
|
|
AIData = query.SearchAICardData(this);
|
|
if (IsAmulet)
|
|
{
|
|
InitializeAmuletTags(query);
|
|
}
|
|
else
|
|
{
|
|
InitializeFollowerTags(query);
|
|
}
|
|
attachedTagCollection?.AttachTagToReceiver(this);
|
|
removedTagCollection?.RemoveTagFromCard(this);
|
|
}
|
|
|
|
public void InitAtSummonToken(AIVirtualCard parent, AISituationInfo situation, bool isSkillSummon, bool isUpdateTokenIndex = true)
|
|
{
|
|
AIPreprocessSimulationUtility.SimulatePreprocess(this, situation, _field, AIScriptTokenArgType.WHEN_SUMMON, isPseudo: false);
|
|
IsOnField = true;
|
|
if (isUpdateTokenIndex)
|
|
{
|
|
if (_field.IsLatestActionField)
|
|
{
|
|
if (IsAlly)
|
|
{
|
|
CardIndex = _field.AllyCardTotalNum;
|
|
_field.AllyCardTotalNum++;
|
|
}
|
|
else
|
|
{
|
|
CardIndex = _field.EnemyCardTotalNum;
|
|
_field.EnemyCardTotalNum++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CardIndex = _field.TokenIndex;
|
|
_field.TokenIndex--;
|
|
}
|
|
}
|
|
parent.AddChildren(CardIndex);
|
|
AttackableCount = MaxAttackableCount;
|
|
IsFirstTurn = true;
|
|
IsSkillSummoned = isSkillSummon;
|
|
if (IsUseEvo)
|
|
{
|
|
AttackableCount = 1;
|
|
AIAutoEvolutionSimulationUtility.AutoEvolveSingle(this, _field, situation);
|
|
}
|
|
}
|
|
|
|
public void PseudoInitAtSummonToken(AIVirtualCard parent, AISituationInfo situation, bool isSkillSummon)
|
|
{
|
|
IsOnField = true;
|
|
AttackableCount = MaxAttackableCount;
|
|
IsFirstTurn = true;
|
|
IsSkillSummoned = isSkillSummon;
|
|
if (IsUseEvo)
|
|
{
|
|
AttackableCount = ((AttackableCount <= 1) ? 1 : AttackableCount);
|
|
AIAutoEvolutionSimulationUtility.AutoEvolveSingle(this, _field, situation);
|
|
}
|
|
}
|
|
|
|
public void InitAtDrawToken(AIVirtualCard parent, AISituationInfo situation)
|
|
{
|
|
AIPreprocessSimulationUtility.SimulatePreprocess(this, situation, _field, AIScriptTokenArgType.TOKEN_DRAW, isPseudo: false);
|
|
IsOnField = false;
|
|
IsInHand = true;
|
|
if (_field.IsLatestActionField)
|
|
{
|
|
if (IsAlly)
|
|
{
|
|
CardIndex = _field.AllyCardTotalNum;
|
|
_field.AllyCardTotalNum++;
|
|
}
|
|
else
|
|
{
|
|
CardIndex = _field.EnemyCardTotalNum;
|
|
_field.EnemyCardTotalNum++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CardIndex = _field.TokenIndex;
|
|
_field.TokenIndex--;
|
|
}
|
|
parent.AddChildren(CardIndex);
|
|
AddToHand();
|
|
}
|
|
|
|
public void InitAtMetamorphose(AIVirtualCard originCard, AIVirtualCard parent)
|
|
{
|
|
IsOnField = true;
|
|
CardIndex = originCard.CardIndex;
|
|
parent.AddChildren(CardIndex);
|
|
AttackableCount = MaxAttackableCount;
|
|
IsFirstTurn = true;
|
|
IsSkillSummoned = false;
|
|
}
|
|
|
|
public void InitAtHandMetamorphose(AIVirtualCard originCard, AIVirtualCard parent)
|
|
{
|
|
IsInHand = true;
|
|
CardIndex = originCard.CardIndex;
|
|
parent.AddChildren(CardIndex);
|
|
}
|
|
|
|
public void ReplaceSelfField(AIVirtualField field)
|
|
{
|
|
_field = field;
|
|
}
|
|
|
|
public void AddChildren(int index)
|
|
{
|
|
if (ChildrenIndexList == null)
|
|
{
|
|
ChildrenIndexList = new List<int>();
|
|
}
|
|
ChildrenIndexList.Add(index);
|
|
}
|
|
|
|
public virtual bool IsFollower(List<int> playPtn)
|
|
{
|
|
if (IsUnit)
|
|
{
|
|
if (!this.IsAccelerated(_field, playPtn))
|
|
{
|
|
return !this.IsCrystalize(_field, playPtn);
|
|
}
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public virtual bool BasePlayable()
|
|
{
|
|
if (!IsAlly || !IsInHand)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool IsHoldKeywordSkill(AIScriptTokenArgType skill)
|
|
{
|
|
return skill switch
|
|
{
|
|
AIScriptTokenArgType.SNEAK => IsSneak,
|
|
AIScriptTokenArgType.KILLER => IsKiller,
|
|
AIScriptTokenArgType.GUARD => IsGuard,
|
|
AIScriptTokenArgType.RUSH => IsRush,
|
|
AIScriptTokenArgType.QUICK => IsQuick,
|
|
AIScriptTokenArgType.DRAIN => IsDrain,
|
|
AIScriptTokenArgType.UNTOUCHABLE => IsUntouchable,
|
|
AIScriptTokenArgType.FORCE_TARGETING => IsForceTargeting,
|
|
AIScriptTokenArgType.UNBANISHABLE => IsUnbanishable,
|
|
AIScriptTokenArgType.IGNORE_GUARD => IsIgnoreGuard,
|
|
_ => false,
|
|
};
|
|
}
|
|
|
|
public bool IsAttackable(List<int> playPtn)
|
|
{
|
|
bool flag = AttackableCount > 0 && !IsCantAttackAll && (!IsSummonDrunkenness || IsEvolution);
|
|
if (IsAlly && !flag && IsInHand && playPtn != null && playPtn.Count > 0)
|
|
{
|
|
for (int i = 0; i < playPtn.Count; i++)
|
|
{
|
|
if (_field.AllyHandCards[playPtn[i]].IsSameCard(this))
|
|
{
|
|
flag = AISkillSimulationUtility.HasSkill(this, AIScriptTokenArgType.QUICK, _field.AI, playPtn) || AISkillSimulationUtility.HasSkill(this, AIScriptTokenArgType.RUSH, _field.AI, playPtn);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return flag;
|
|
}
|
|
|
|
public bool IsEvolDrunkenness()
|
|
{
|
|
if (IsFirstTurn && IsSummonDrunkenness)
|
|
{
|
|
return !IsQuick;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool IsCantAttackClass()
|
|
{
|
|
if (!IsSkillCantAttackClass && !IsEvolDrunkenness())
|
|
{
|
|
if (IsFirstTurn && IsRush)
|
|
{
|
|
return !IsQuick;
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public void RecoverAttackableCount()
|
|
{
|
|
AttackableCount = MaxAttackableCount;
|
|
IsRecoveredAttackableCount = true;
|
|
}
|
|
|
|
public void ChangeClass(CardBasePrm.ClanType classType)
|
|
{
|
|
if (classType >= CardBasePrm.ClanType.ALL && classType < CardBasePrm.ClanType.MAX)
|
|
{
|
|
Clan = classType;
|
|
}
|
|
}
|
|
|
|
public bool IsTribe(AIScriptTokenArgType tribeType)
|
|
{
|
|
CardBasePrm.TribeType tribeType2 = AITribeSimulationUtility.ConvertTokenArgTypeToTribeType(tribeType);
|
|
if (tribeType2 >= CardBasePrm.TribeType.MAX)
|
|
{
|
|
return false;
|
|
}
|
|
return IsTribe(tribeType2);
|
|
}
|
|
|
|
public void AppendTribe(CardBasePrm.TribeType tribe)
|
|
{
|
|
if (_tribeList == null)
|
|
{
|
|
_tribeList = new List<CardBasePrm.TribeType>();
|
|
}
|
|
if (!_tribeList.Contains(tribe))
|
|
{
|
|
_tribeList.Add(tribe);
|
|
}
|
|
}
|
|
|
|
public void ChangeTribe(CardBasePrm.TribeType tribe)
|
|
{
|
|
if (_tribeList == null)
|
|
{
|
|
_tribeList = new List<CardBasePrm.TribeType>();
|
|
}
|
|
else
|
|
{
|
|
_tribeList.Clear();
|
|
}
|
|
_tribeList.Add(tribe);
|
|
}
|
|
|
|
public float UpdateValue(AIParamQuery paramQuery, AIStyleQuery styleQuery, List<int> playPtn, bool doesUseLostLife)
|
|
{
|
|
if (IsDead)
|
|
{
|
|
Value = 0f;
|
|
return Value;
|
|
}
|
|
if (IsUnit)
|
|
{
|
|
if (Life <= 0)
|
|
{
|
|
Value = 0f;
|
|
return Value;
|
|
}
|
|
Value = this.EvaluateValueOnField(playPtn, null, useStyle: true, doesUseLostLife, useOthersTag: true, useIgnoreInBattle: true);
|
|
Value += (this.GetAllBreakBonus(playPtn, useIgnoreInBattle: false) + this.GetAllLeaveBonus(playPtn, useIgnoreInBattle: false)) * EnemyAI.BREAKBONUS_RATE_ON_FIELD;
|
|
}
|
|
else if (IsLeader)
|
|
{
|
|
Value = this.GetBattleBonus(playPtn);
|
|
}
|
|
else
|
|
{
|
|
Value = this.GetFieldBonus(playPtn);
|
|
}
|
|
return Value;
|
|
}
|
|
|
|
public void SetDefaultValue()
|
|
{
|
|
DefaultValue = Value;
|
|
}
|
|
|
|
public int SimulateAttackAmount(AISituationInfo situation)
|
|
{
|
|
return SimulateAttackAmount(Attack, situation);
|
|
}
|
|
|
|
public int SimulateAttackAmount(int attack, AISituationInfo situation)
|
|
{
|
|
return _field.DamageModifierCollection.CalcModifiedDamage(_field, EnemyAI.EmptyPlayPtn, situation, this, attack);
|
|
}
|
|
|
|
public int SimulateDamageAmount(int damageAmount, bool isSkillDamage = false, bool isSpellDamage = false)
|
|
{
|
|
damageAmount = BarrierInfoCollection.CalcDamageAmount(this, damageAmount, isSkillDamage, isSpellDamage);
|
|
return Math.Max(damageAmount, 0);
|
|
}
|
|
|
|
public int SimulateDamageShield(int damageAmount, bool isSkillDamage = false, bool isSpellDamage = false)
|
|
{
|
|
bool flag = !isSkillDamage && !isSpellDamage;
|
|
if ((isSkillDamage && BarrierInfoCollection.HasShieldSkill) || (isSpellDamage && BarrierInfoCollection.HasShieldSpell) || (flag && BarrierInfoCollection.HasShieldAttack))
|
|
{
|
|
return 0;
|
|
}
|
|
return damageAmount;
|
|
}
|
|
|
|
public int AddDamage(AISituationInfo situation, int baseDamage, bool isSkillDamage)
|
|
{
|
|
if (IsDead)
|
|
{
|
|
return 0;
|
|
}
|
|
bool isSpellDamage = situation.ActionType == AIOperationType.PLAY && situation.Actor.IsSpell;
|
|
int num = SimulateDamageAmount(baseDamage, isSkillDamage, isSpellDamage);
|
|
Life -= num;
|
|
if (Life > 0)
|
|
{
|
|
LastLife = Life;
|
|
SelfField.DamagedCardsByLastAction.Add(new Tuple<AIVirtualCard, int>(this, num));
|
|
}
|
|
else
|
|
{
|
|
IsDead = true;
|
|
}
|
|
_field.TagPreprocessContainer.SimulateAfterDamageInfo(this);
|
|
_field.ExecuteWhenDamageTags(this, baseDamage, SelfField.BestPlayPtn, situation);
|
|
_field.AllActivateCountHolderIncrement(situation, AIPlayTagType.DamagedActivateCount, this);
|
|
return num;
|
|
}
|
|
|
|
public void Heal(int healLife)
|
|
{
|
|
if (!IsDead)
|
|
{
|
|
int life = Life;
|
|
Life = Math.Min(Life + healLife, MaxLife);
|
|
LastHealAmount = Life - life;
|
|
LastLife = Life;
|
|
int turn = (IsAlly ? _field.AllyTurnCount : _field.EnemyTurnCount);
|
|
_field.HealRecorderCollection.AppendHealCount(turn, this, IsAlly);
|
|
}
|
|
}
|
|
|
|
private void ModifyAttack(int buff, bool isMultiply, bool isTemp)
|
|
{
|
|
int attack = Attack;
|
|
if (isMultiply)
|
|
{
|
|
Attack *= buff;
|
|
}
|
|
else
|
|
{
|
|
Attack += buff;
|
|
}
|
|
if (isTemp)
|
|
{
|
|
TempAtkBuff += Attack - attack;
|
|
}
|
|
}
|
|
|
|
private void ModifyLife(AISituationInfo situation, int buff, bool isMultiply, bool isTemp)
|
|
{
|
|
int life = Life;
|
|
if (isMultiply)
|
|
{
|
|
Life *= buff;
|
|
}
|
|
else
|
|
{
|
|
Life += buff;
|
|
}
|
|
if (Life <= 0)
|
|
{
|
|
RemoveCard(situation, AIRemovalType.Destroy, isFromSkill: false);
|
|
}
|
|
int newLife = (isMultiply ? (MaxLife * buff) : (MaxLife + buff));
|
|
SetMaxLife(situation, newLife);
|
|
if (isTemp && !IsDead)
|
|
{
|
|
TempLifeBuff += Life - life;
|
|
}
|
|
LastLife = Life;
|
|
}
|
|
|
|
public void GiveBuff(AISituationInfo situation, AIBuffExecutingInfo_old buff, bool isTemp)
|
|
{
|
|
int attack = Attack;
|
|
int life = Life;
|
|
ModifyAttack(buff.AttackValue, buff.IsMultiplyAttack, isTemp);
|
|
ModifyLife(situation, buff.LifeValue, buff.IsMultiplyLife, isTemp);
|
|
int turn = (IsAlly ? _field.AllyTurnCount : _field.EnemyTurnCount);
|
|
if (BuffRecorderCollection == null)
|
|
{
|
|
BuffRecorderCollection = new AIBuffRecorderCollection();
|
|
}
|
|
int atkBuff = Attack - attack;
|
|
int lifeBuff = Life - life;
|
|
BuffRecorderCollection.AddBuffRecord(turn, IsSelfTurn, atkBuff, lifeBuff);
|
|
if (isTemp)
|
|
{
|
|
AIBuffStopPreprocessOption option = new AIBuffStopPreprocessOption(this);
|
|
_field.TagPreprocessContainer.AppendAllyTurnEndStopInfo(option);
|
|
_field.TagPreprocessContainer.AppendOpponentTurnEndStopInfo(option);
|
|
}
|
|
}
|
|
|
|
public void MultiplyAttack(int rate)
|
|
{
|
|
Attack *= rate;
|
|
}
|
|
|
|
public void MultiplyLife(int rate)
|
|
{
|
|
Life *= rate;
|
|
}
|
|
|
|
public void SetAttack(int newAttack)
|
|
{
|
|
Attack = newAttack;
|
|
}
|
|
|
|
public void SetLife(int newLife, AISituationInfo situation)
|
|
{
|
|
Life = newLife;
|
|
MaxLife = newLife;
|
|
TempLifeBuff = 0;
|
|
if (Life <= 0)
|
|
{
|
|
RemoveCard(situation, AIRemovalType.Destroy, isFromSkill: false);
|
|
}
|
|
}
|
|
|
|
public void SetMaxLife(AISituationInfo situation, int newLife)
|
|
{
|
|
MaxLife = newLife;
|
|
if (Life > MaxLife)
|
|
{
|
|
Life = MaxLife;
|
|
}
|
|
if (Life <= 0)
|
|
{
|
|
RemoveCard(situation, AIRemovalType.Destroy, isFromSkill: false);
|
|
}
|
|
}
|
|
|
|
public void SetNewStatus(AISituationInfo situation, int newAttack, int newLife)
|
|
{
|
|
Attack = newAttack;
|
|
Life = newLife;
|
|
SetMaxLife(situation, newLife);
|
|
LastLife = Life;
|
|
TempAtkBuff = 0;
|
|
TempLifeBuff = 0;
|
|
}
|
|
|
|
public void ChantCountDown(AISituationInfo situation, int value)
|
|
{
|
|
ChantCount -= value;
|
|
if (ChantCount <= 0)
|
|
{
|
|
RemoveCard(situation, AIRemovalType.Destroy, isFromSkill: false);
|
|
}
|
|
}
|
|
|
|
public int EarthRite(int count, AISituationInfo situation, bool isPseudo)
|
|
{
|
|
int num = Math.Min(WhiteRitualCount, count);
|
|
WhiteRitualCount -= num;
|
|
if (!isPseudo)
|
|
{
|
|
_originalWhiteRitualCount -= num;
|
|
}
|
|
if (WhiteRitualCount <= 0)
|
|
{
|
|
if (isPseudo)
|
|
{
|
|
IsDead = true;
|
|
}
|
|
else
|
|
{
|
|
Destroy(situation, isFromSkill: true);
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public void SetWhiteRitual(int count)
|
|
{
|
|
if (count <= 0)
|
|
{
|
|
AIConsoleUtility.LogError($"SetWhiteRitual : Ilegal add count Error [count={count}]");
|
|
}
|
|
else if (!IsDead && IsStackWhiteRitual && WhiteRitualCount > 0)
|
|
{
|
|
WhiteRitualCount = count;
|
|
}
|
|
}
|
|
|
|
public bool AddWhiteRitual(int count)
|
|
{
|
|
if (count <= 0)
|
|
{
|
|
AIConsoleUtility.LogError($"AddWhiteRitual : Ilegal add count Error [count={count}]");
|
|
return false;
|
|
}
|
|
if (IsDead || !IsStackWhiteRitual || WhiteRitualCount <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
WhiteRitualCount += count;
|
|
return true;
|
|
}
|
|
|
|
public void ResetEarthRite(int resetCount)
|
|
{
|
|
if (WhiteRitualCount <= 0 && IsDead)
|
|
{
|
|
IsDead = false;
|
|
}
|
|
WhiteRitualCount += Mathf.Max(0, resetCount);
|
|
}
|
|
|
|
public void ResetAllEvaluationUpdatedParameter()
|
|
{
|
|
if (WhiteRitualCount <= 0 && IsDead)
|
|
{
|
|
IsDead = false;
|
|
}
|
|
WhiteRitualCount = _originalWhiteRitualCount;
|
|
}
|
|
|
|
public void ChangeIsCantUnderAttack(bool isCantUnderAttack)
|
|
{
|
|
_isCantUnderAttack = isCantUnderAttack;
|
|
}
|
|
|
|
public void RegisterGiveSneakTag(AIPlayTag tag)
|
|
{
|
|
_giveSneakTagList = AIParamQuery.AddElementToList(tag, _giveSneakTagList);
|
|
}
|
|
|
|
public void DepriveSneakWithGiveSneakTag()
|
|
{
|
|
IsSneak = false;
|
|
if (_giveSneakTagList != null && _giveSneakTagList.Count > 0)
|
|
{
|
|
for (int i = 0; i < _giveSneakTagList.Count; i++)
|
|
{
|
|
AIPlayTag removingTag = _giveSneakTagList[i];
|
|
TagCollectionContainer.RemoveOneTagWithUpdatingFieldCardList(this, removingTag, SelfField);
|
|
}
|
|
_giveSneakTagList.Clear();
|
|
}
|
|
}
|
|
|
|
public bool IsCantUnderAttack(AIParamQuery query, AIVirtualCard attacker, List<int> playPtn, AIVirtualField field)
|
|
{
|
|
if (TagCollectionContainer.HasTag(AIPlayTagType.CantBeAttacked) && TagCollectionContainer.CantBeAttackedTags.CantBeAttacked(this, attacker, playPtn, field))
|
|
{
|
|
return false;
|
|
}
|
|
return _isCantUnderAttack;
|
|
}
|
|
|
|
public bool IsCantUnderAnyAttack()
|
|
{
|
|
return _isCantUnderAttack;
|
|
}
|
|
|
|
public void AfterClash(AIVirtualCard clashTarget, int finalDamage, bool isAttacker, List<int> playPtn, AIVirtualAttackInfo situation)
|
|
{
|
|
if (!clashTarget.IsIndependent && IsKiller)
|
|
{
|
|
clashTarget.RemoveCard(situation, AIRemovalType.Destroy, isFromSkill: true);
|
|
}
|
|
if (isAttacker)
|
|
{
|
|
if (IsSneak)
|
|
{
|
|
DepriveSneakWithGiveSneakTag();
|
|
}
|
|
DealDamageDrain(finalDamage, playPtn, situation);
|
|
}
|
|
if (Life <= 0 && !IsDead)
|
|
{
|
|
RemoveCard(situation, AIRemovalType.Destroy, isFromSkill: false);
|
|
}
|
|
}
|
|
|
|
public void DealDamageDrain(int damage, List<int> playPtn, AISituationInfo situation)
|
|
{
|
|
if (IsDrain && damage >= 0)
|
|
{
|
|
AISkillSimulationUtility.HealSingle(IsAlly ? _field.AllyClass : _field.EnemyClass, SelfField, damage, playPtn, situation);
|
|
}
|
|
}
|
|
|
|
public void RemoveTempBuff()
|
|
{
|
|
if (TempAtkBuff != 0)
|
|
{
|
|
Attack -= TempAtkBuff;
|
|
TempAtkBuff = 0;
|
|
}
|
|
if (TempLifeBuff != 0)
|
|
{
|
|
Life -= TempLifeBuff;
|
|
LastLife = Life;
|
|
TempLifeBuff = 0;
|
|
}
|
|
}
|
|
|
|
public bool IsEqual(BattleCardBase card)
|
|
{
|
|
if (card.Index == CardIndex && _field.AI.IsAllyCard(card) == IsAlly)
|
|
{
|
|
return card.BaseParameter.BaseCardId == BaseId;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool IsSameCard(AIVirtualCard card)
|
|
{
|
|
if (card.CardIndex == CardIndex && card.IsAlly == IsAlly)
|
|
{
|
|
return card.BaseParameter.BaseId == BaseParameter.BaseId;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool IsSameCardType(AIVirtualCard card)
|
|
{
|
|
if (card.IsUnit == IsUnit && card.IsSpell == IsSpell)
|
|
{
|
|
return (card.IsAmulet || card.IsCountdownAmulet) == (IsAmulet || IsCountdownAmulet);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool IsSameCardIncluded(List<AIVirtualCard> list)
|
|
{
|
|
if (list == null || list.Count <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
for (int i = 0; i < list.Count; i++)
|
|
{
|
|
AIVirtualCard card = list[i];
|
|
if (IsSameCard(card))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void NormalPlay()
|
|
{
|
|
IsOnField = true;
|
|
IsInHand = false;
|
|
IsFirstTurn = true;
|
|
AttackableCount = MaxAttackableCount;
|
|
IsSummonDrunkenness = !IsQuick && !IsRush;
|
|
}
|
|
|
|
public void ResetPosition(AIOperationType actionType)
|
|
{
|
|
if (actionType == AIOperationType.PLAY)
|
|
{
|
|
IsInHand = true;
|
|
IsOnField = false;
|
|
}
|
|
}
|
|
|
|
public void EvolveStatusUp()
|
|
{
|
|
Life += EvoLifePlus;
|
|
LastLife = Life;
|
|
MaxLife += EvoLifePlus;
|
|
Attack += EvoAttackPlus;
|
|
IsEvolution = true;
|
|
}
|
|
|
|
public void AddToHand()
|
|
{
|
|
IsInHand = true;
|
|
IsOnField = false;
|
|
if (IsAlly)
|
|
{
|
|
_field.AllyHandCards.Add(this);
|
|
}
|
|
else
|
|
{
|
|
_field.GetEnemyHandCardList().Add(this);
|
|
}
|
|
_field.CardListSet.AddHandCard(this);
|
|
}
|
|
|
|
private void LeaveFromField(AISituationInfo situation)
|
|
{
|
|
IsDead = true;
|
|
IsOnField = false;
|
|
_isCompletedRemove = true;
|
|
if (IsAlly)
|
|
{
|
|
_field.CardListSet.AddAllyLeftCard(this);
|
|
_field.CardListSet.AddAllyLeftCardThisTurn(this);
|
|
}
|
|
else
|
|
{
|
|
_field.CardListSet.AddEnemyLeftCard(this);
|
|
_field.CardListSet.AddEnemyLeftCardThisTurn(this);
|
|
}
|
|
_field.WhenCardLeaveFromField(this, situation);
|
|
GetOff(situation);
|
|
}
|
|
|
|
private void ExecuteLeaveSkills(AISituationInfo situation)
|
|
{
|
|
_field.SimulationExtraBonus += (float)(IsAlly ? 1 : (-1)) * this.GetAllLeaveBonus(_field.BestPlayPtn, useIgnoreInBattle: true);
|
|
if (TagCollectionContainer.HasTagCollection(TagCollectionType.WhenLeave))
|
|
{
|
|
TagCollectionContainer.LeaveTags.Execute(this, _field.BestPlayPtn, situation);
|
|
}
|
|
if (!_field.CardListSet.HasLeaveOtherTagHolders)
|
|
{
|
|
return;
|
|
}
|
|
for (int i = 0; i < _field.CardListSet.WhenLeaveOtherTagHolders.Count; i++)
|
|
{
|
|
AIVirtualCard aIVirtualCard = _field.CardListSet.WhenLeaveOtherTagHolders[i];
|
|
if (!aIVirtualCard.IsSameCard(this))
|
|
{
|
|
aIVirtualCard.TagCollectionContainer.OtherLeaveTags.RegisterPassedConditionTags(aIVirtualCard, SelfField, SelfField.BestPlayPtn, situation, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Destroy(AISituationInfo situation, bool isFromSkill)
|
|
{
|
|
if (_field == null || _isCompletedRemove || (isFromSkill && IsIndestructible))
|
|
{
|
|
return;
|
|
}
|
|
AISkillProcessInformation processInfo = situation.RegisterNewProcessInfo(this, AISituationTriggerInformation.TriggerType.Undefined);
|
|
List<int> emptyPlayPtn = EnemyAI.EmptyPlayPtn;
|
|
situation.RegisterOwnDestroyedCard(this);
|
|
LeaveFromField(situation);
|
|
_field.ExecuteWhenChangeInplayTags(emptyPlayPtn, situation);
|
|
ExecuteLeaveSkills(situation);
|
|
if (IsLeader)
|
|
{
|
|
return;
|
|
}
|
|
_field.VirtualCemetery.AddCemetery(1, IsAlly);
|
|
if (TagCollectionContainer.HasTag(AIPlayTagType.RemoveSkill))
|
|
{
|
|
TagCollectionContainer.RemoveSkillTags.Execute(this, AIScriptTokenArgType.WHEN_DESTROY, null);
|
|
}
|
|
if (this.IsBreakBeforePlay(_field.BestPlayPtn))
|
|
{
|
|
_field.IsBreakBeforePlayKilled = true;
|
|
}
|
|
if (!IsSkillLost && (this.HasBreakBonus(_field) || TagCollectionContainer.HasTagCollection(TagCollectionType.Lastword)))
|
|
{
|
|
if (IsAmulet)
|
|
{
|
|
_field.SimulationExtraBonus += (float)(IsAlly ? 1 : (-1)) * this.GetAllBreakBonus(_field.BestPlayPtn, useIgnoreInBattle: true);
|
|
ExecuteLastwordSkills(processInfo, situation);
|
|
}
|
|
else
|
|
{
|
|
AIVirtualCard aIVirtualCard = (IsAlly ? _field.AllyClass : _field.EnemyClass);
|
|
int num = 1;
|
|
if (aIVirtualCard.TagCollectionContainer.HasTag(AIPlayTagType.OneMoreLastword) && aIVirtualCard.TagCollectionContainer.OneMoreLastwordTags.CheckConditionAndRemovePassedTags(aIVirtualCard, _field, situation))
|
|
{
|
|
num++;
|
|
}
|
|
_field.SimulationExtraBonus += (float)(IsAlly ? 1 : (-1)) * this.GetBreakBonus(_field.BestPlayPtn, useIgnoreBreak: true) * (float)num;
|
|
_field.SimulationExtraBonus += (float)(IsAlly ? 1 : (-1)) * AIEvaluateBonusFromOhterUtility.GetOtherBreakBonus(this, _field, _field.BestPlayPtn, useIgnoreInBattle: true);
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
ExecuteLastwordSkills(processInfo, situation);
|
|
}
|
|
}
|
|
}
|
|
if (IsAlly)
|
|
{
|
|
_field.CardListSet.AddAllyDestroyedCard(this, isDestroyTurn: true);
|
|
}
|
|
else
|
|
{
|
|
_field.CardListSet.AddEnemyDestroyedCard(this);
|
|
}
|
|
if (SelfField.CardListSet.HasBreakTagHolder)
|
|
{
|
|
ApplyWhenDestroyTags(situation);
|
|
}
|
|
_field.AllActivateCountHolderIncrement(situation, AIPlayTagType.BreakActivateCount, this);
|
|
}
|
|
|
|
public void BurialRite()
|
|
{
|
|
if (IsInHand)
|
|
{
|
|
IsInHand = false;
|
|
_field.RemoveAllyHandCard(this);
|
|
_field.VirtualCemetery.AddCemetery(1, IsAlly);
|
|
}
|
|
}
|
|
|
|
private void ExecuteLastwordSkills(AISkillProcessInformation processInfo, AISituationInfo situation)
|
|
{
|
|
AIPreprocessSimulationUtility.SimulatePreprocess(this, situation, _field, AIScriptTokenArgType.WHEN_DESTROY, isPseudo: false);
|
|
if (TagCollectionContainer.HasTagCollection(TagCollectionType.Lastword))
|
|
{
|
|
TagCollectionContainer.LastwordTags.RegisterExecutingTagActions(this, processInfo, situation);
|
|
}
|
|
situation.ProcessCollection.CombinePreprocessToProcessQueue();
|
|
}
|
|
|
|
private void Banish(AISituationInfo situation)
|
|
{
|
|
if (!_isCompletedRemove)
|
|
{
|
|
if (situation == null)
|
|
{
|
|
AIConsoleUtility.LogError("AIVirtualCard.Banish() error!! situation == null!!!!!");
|
|
}
|
|
situation.RegisterNewProcessInfo(this, AISituationTriggerInformation.TriggerType.Banish);
|
|
List<int> emptyPlayPtn = EnemyAI.EmptyPlayPtn;
|
|
SetBanishedCardInfo();
|
|
situation.RegisterOwnBanishedCard(this);
|
|
LeaveFromField(situation);
|
|
_field.ExecuteWhenChangeInplayTags(emptyPlayPtn, situation);
|
|
ExecuteLeaveSkills(situation);
|
|
ApplyWhenBanishTags(situation);
|
|
_field.AllActivateCountHolderIncrement(situation, AIPlayTagType.BanishActivateCount, this);
|
|
_field.CardListSet.AddBanishedCard(this);
|
|
}
|
|
}
|
|
|
|
private void SetBanishedCardInfo()
|
|
{
|
|
if (_field == null)
|
|
{
|
|
AIConsoleUtility.LogError("SetBanishedCardInfo() Error : Field is Null");
|
|
return;
|
|
}
|
|
int currentTurnCount = _field.CurrentTurnCount;
|
|
BattleCardBase.BanishInfo.BanishPlace place = (IsOnField ? BattleCardBase.BanishInfo.BanishPlace.Field : (IsInHand ? BattleCardBase.BanishInfo.BanishPlace.Hand : BattleCardBase.BanishInfo.BanishPlace.Deck));
|
|
BanishedInfo = new AIVirtualBanishInfo(currentTurnCount, IsSelfTurn, place);
|
|
}
|
|
|
|
public bool IsBanishedTargetTurn(int turn)
|
|
{
|
|
if (BanishedInfo == null)
|
|
{
|
|
return false;
|
|
}
|
|
if (BanishedInfo.Place == BattleCardBase.BanishInfo.BanishPlace.None || BanishedInfo.Place == BattleCardBase.BanishInfo.BanishPlace.Deck)
|
|
{
|
|
return false;
|
|
}
|
|
if (BanishedInfo.Turn != turn || BanishedInfo.IsCardOwnerTurn != IsSelfTurn)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void ConvertBaseBanishInfo(BattleCardBase.BanishInfo baseInfo)
|
|
{
|
|
if (baseInfo == null)
|
|
{
|
|
AIConsoleUtility.LogError("ConvertBaseBanishInfo() : convert target is Null");
|
|
return;
|
|
}
|
|
bool isSelfTurn = baseInfo.IsSelfTurn;
|
|
bool isCardOwnerTurn = (IsPlayer ? isSelfTurn : (!isSelfTurn));
|
|
BanishedInfo = new AIVirtualBanishInfo(baseInfo.Turn, isCardOwnerTurn, baseInfo.Place);
|
|
}
|
|
|
|
public void MetamorphoseLeave(AISituationInfo situation)
|
|
{
|
|
if (!_isCompletedRemove)
|
|
{
|
|
IsDead = true;
|
|
IsOnField = false;
|
|
LeaveFromField(situation);
|
|
}
|
|
}
|
|
|
|
private void Bounce(AISituationInfo situation)
|
|
{
|
|
if (!_isCompletedRemove)
|
|
{
|
|
_field.SimulationExtraBonus += (float)(IsAlly ? 1 : (-1)) * this.GetBounceBonus();
|
|
LeaveFromField(situation);
|
|
ExecuteLeaveSkills(situation);
|
|
List<int> emptyPlayPtn = EnemyAI.EmptyPlayPtn;
|
|
situation.BounceCardList = AIParamQuery.AddElementToList(this, situation.BounceCardList);
|
|
this.ExecuteBounceSkills(this, _field, emptyPlayPtn, situation);
|
|
List<AIVirtualCard> list;
|
|
if (IsAlly)
|
|
{
|
|
list = _field.AllyHandCards;
|
|
_field.AllyInplayCards.Remove(this);
|
|
_field.CardListSet.RemoveAllyInplayCard(this);
|
|
}
|
|
else
|
|
{
|
|
list = _field.GetEnemyHandCardList();
|
|
_field.EnemyInplayCards.Remove(this);
|
|
_field.CardListSet.RemoveEnemyInplayCard(this);
|
|
}
|
|
if (list.Count >= 9)
|
|
{
|
|
_field.VirtualCemetery.AddCemetery(1, IsAlly);
|
|
}
|
|
else
|
|
{
|
|
AIVirtualCard aIVirtualCard = new AIVirtualCard(BaseCard, _field)
|
|
{
|
|
IsInHand = true
|
|
};
|
|
aIVirtualCard.InitializeTags(_field.ParamQuery, null, null);
|
|
list.Add(aIVirtualCard);
|
|
_field.CardListSet.AddHandCard(aIVirtualCard);
|
|
}
|
|
_field.ExecuteWhenChangeInplayTags(emptyPlayPtn, situation);
|
|
}
|
|
}
|
|
|
|
public void Reanimate(AISituationInfo situation)
|
|
{
|
|
if (this.IsReanimateEvo(_field.BestPlayPtn))
|
|
{
|
|
AttackableCount = 1;
|
|
AIAutoEvolutionSimulationUtility.AutoEvolveSingle(this, _field, situation);
|
|
}
|
|
}
|
|
|
|
public void GetOn(AIVirtualCard rideCard, AISituationInfo situation)
|
|
{
|
|
if (TagCollectionContainer.HasTag(AIPlayTagType.GetOn) && rideCard != null && rideCard.IsAlly == IsAlly && rideCard.IsUnit && !IsGetOn)
|
|
{
|
|
GetOnCardId = rideCard.BaseId;
|
|
rideCard.ToRide();
|
|
IsCantAttackAll = false;
|
|
IsSkillCantAttackUnit = false;
|
|
List<int> emptyPlayPtn = EnemyAI.EmptyPlayPtn;
|
|
_field.ExecuteWhenChangeInplayTags(emptyPlayPtn, situation);
|
|
AIGetOnSimulationUtility.ExecuteGetOnTriggerTags(this, _field, situation);
|
|
}
|
|
}
|
|
|
|
public void GetOff(AISituationInfo situation)
|
|
{
|
|
if (IsGetOn)
|
|
{
|
|
GetOffCard = AIGetOnSimulationUtility.GetoffTokenOnVirtualField(GetOnCardId, this, _field, situation);
|
|
List<int> emptyPlayPtn = EnemyAI.EmptyPlayPtn;
|
|
_field.ExecuteWhenChangeInplayTags(emptyPlayPtn, situation);
|
|
}
|
|
}
|
|
|
|
public void ToRide()
|
|
{
|
|
IsDead = true;
|
|
}
|
|
|
|
public void Spellboost(int count)
|
|
{
|
|
if (IsInHand && HasSpellboost)
|
|
{
|
|
SpellboostCount += count;
|
|
}
|
|
}
|
|
|
|
public void SetSpellboostCount(int count)
|
|
{
|
|
SpellboostCount = count;
|
|
}
|
|
|
|
public float EvaluateClashBonus()
|
|
{
|
|
if (!TagCollectionContainer.HasTagCollection(TagCollectionType.ClashBonus))
|
|
{
|
|
return 0f;
|
|
}
|
|
return TagCollectionContainer.ClashBonusTags.GetClashBonus(this, SelfField, SelfField.BestPlayPtn);
|
|
}
|
|
|
|
private void ApplyWhenDestroyTags(AISituationInfo situation)
|
|
{
|
|
for (int i = 0; i < SelfField.CardListSet.BreakTagHolders.Count; i++)
|
|
{
|
|
AIVirtualCard aIVirtualCard = SelfField.CardListSet.BreakTagHolders[i];
|
|
if (!aIVirtualCard.IsDead && (aIVirtualCard.CardIndex != CardIndex || aIVirtualCard.BaseId != BaseId) && aIVirtualCard.TagCollectionContainer.HasTagCollection(TagCollectionType.WhenBreak))
|
|
{
|
|
aIVirtualCard.TagCollectionContainer.BreakTags.RegisterExecutingTagActions(SelfField, aIVirtualCard, this, SelfField.BestPlayPtn, situation);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ApplyWhenBanishTags(AISituationInfo situation)
|
|
{
|
|
if (TagCollectionContainer.HasTagCollection(TagCollectionType.WhenBanish))
|
|
{
|
|
TagCollectionContainer.BanishTags.RegisterExecutingTagActions(SelfField, this, SelfField.BestPlayPtn, situation);
|
|
}
|
|
if (!SelfField.CardListSet.HasBanishTagHolder)
|
|
{
|
|
return;
|
|
}
|
|
for (int i = 0; i < SelfField.CardListSet.BanishTagHolders.Count; i++)
|
|
{
|
|
AIVirtualCard aIVirtualCard = SelfField.CardListSet.BanishTagHolders[i];
|
|
if (!aIVirtualCard.IsDead && !aIVirtualCard.IsSameCard(this) && aIVirtualCard.TagCollectionContainer.HasTagCollection(TagCollectionType.WhenOtherBanish))
|
|
{
|
|
aIVirtualCard.TagCollectionContainer.OtherBanishTags.RegisterExecutingTagActions(SelfField, aIVirtualCard, this, SelfField.BestPlayPtn, situation);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void GiveAttackable()
|
|
{
|
|
IsCantAttackAll = false;
|
|
IsSkillCantAttackUnit = false;
|
|
IsSkillCantAttackClass = false;
|
|
}
|
|
|
|
public void GiveAttackableCount(int count)
|
|
{
|
|
int maxAttackableCount = MaxAttackableCount;
|
|
if (count > maxAttackableCount)
|
|
{
|
|
AttackableCount = Math.Min(AttackableCount + (count - maxAttackableCount), count);
|
|
}
|
|
else if (count < maxAttackableCount)
|
|
{
|
|
AttackableCount = Math.Min(count, AttackableCount);
|
|
}
|
|
MaxAttackableCount = count;
|
|
}
|
|
|
|
public void RemoveAllSkills(AISituationInfo situation)
|
|
{
|
|
DepriveSneakWithGiveSneakTag();
|
|
IsKiller = false;
|
|
IsDrain = false;
|
|
IsRush = false;
|
|
IsQuick = false;
|
|
IsDestroyWhenAttack = false;
|
|
HasSpellboost = false;
|
|
IsForceTargeting = false;
|
|
IsUnbanishable = false;
|
|
UntouchableCount = 0;
|
|
_bounceByBanishCount = 0;
|
|
_banishByDestroyCount = 0;
|
|
_destroyByBanishCount = 0;
|
|
TagCollectionContainer.RemoveAllTagWithUpdatingFieldCardList(this, SelfField, situation);
|
|
IsSkillLost = true;
|
|
}
|
|
|
|
public void CallOnAfterBattleSimulation(AIVirtualTurnEndInfo turnEndSituation)
|
|
{
|
|
turnEndSituation.ProcessCollection.ClearTempPreprocessList();
|
|
AIPreprocessSimulationUtility.SimulatePreprocess(this, turnEndSituation, _field, AIScriptTokenArgType.WHEN_TURNEND, isPseudo: false);
|
|
AISkillProcessInformation aISkillProcessInformation = turnEndSituation.RegisterNewProcessInfo(null, AISituationTriggerInformation.TriggerType.Undefined);
|
|
if (TagCollectionContainer.HasTagCollection(TagCollectionType.WhenTurnEnd))
|
|
{
|
|
TurnEndTagCollection turnEndTags = TagCollectionContainer.TurnEndTags;
|
|
if (turnEndTags.HasTagExecuteWhenAllyTurnEnd(turnEndSituation.Actor.IsAlly == IsAlly))
|
|
{
|
|
turnEndTags.RegisterConditionPassedTagActions(this, SelfField.BestPlayPtn, turnEndSituation, aISkillProcessInformation);
|
|
}
|
|
}
|
|
turnEndSituation.ProcessCollection.CombinePreprocessToProcessQueue();
|
|
aISkillProcessInformation.AddExecutingAction(delegate
|
|
{
|
|
if (!turnEndSituation.Actor.IsLeader)
|
|
{
|
|
AIConsoleUtility.LogError("turnEndSituation.Actor is not Leader!!");
|
|
}
|
|
else
|
|
{
|
|
this.Increment(turnEndSituation, AIPlayTagType.TurnEndActivateCount);
|
|
}
|
|
});
|
|
}
|
|
|
|
public bool IsAbleEvolution()
|
|
{
|
|
if (!IsUnit)
|
|
{
|
|
return false;
|
|
}
|
|
if (IsEvolution)
|
|
{
|
|
return false;
|
|
}
|
|
if (!_field.IsExceededWaitEvolveTurn)
|
|
{
|
|
return false;
|
|
}
|
|
if (!_field.IsLeftTurnEvol)
|
|
{
|
|
return false;
|
|
}
|
|
if (_field.AllyEvolutionCount <= 0 && !IsNotConsumeEp)
|
|
{
|
|
return false;
|
|
}
|
|
if (IsDebuffCantEvolve)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool IsAbleToPlay(List<int> playPtn, AIVirtualTargetSelectAction playSituation)
|
|
{
|
|
if (playSituation == null)
|
|
{
|
|
AIConsoleUtility.LogError("IsAbleToPlay() : situation is null");
|
|
return false;
|
|
}
|
|
return AIPlayCardSimulationUtility.IsAbleToPlayCard(playSituation, _field, playPtn);
|
|
}
|
|
|
|
public int GetUseCost(int restPp, List<int> playPtn, AISituationInfo situation, out PlaySimulationType playType)
|
|
{
|
|
int result = GetPlayEnhancedCost(restPp, out playType);
|
|
if (playType == PlaySimulationType.Undefined)
|
|
{
|
|
result = GetPlayChoiceTransformedCost(restPp, playPtn, situation, out playType);
|
|
}
|
|
if (playType == PlaySimulationType.Undefined)
|
|
{
|
|
result = GetPlayNormalCost(restPp, playPtn, situation, out playType);
|
|
}
|
|
if (playType == PlaySimulationType.Undefined)
|
|
{
|
|
result = GetPlayAcceleratedCost(restPp, playPtn, situation, out playType);
|
|
}
|
|
if (playType == PlaySimulationType.Undefined)
|
|
{
|
|
result = GetPlayCrystalizedCost(restPp, out playType);
|
|
}
|
|
if (situation is AIVirtualActionInfo aIVirtualActionInfo)
|
|
{
|
|
aIVirtualActionInfo.ReservedPlayType = playType;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public bool IsPlayingSimulationType(int restPp, List<int> playPtn, AISituationInfo situation, PlaySimulationType checkPlayType)
|
|
{
|
|
PlaySimulationType playType = PlaySimulationType.Undefined;
|
|
switch (checkPlayType)
|
|
{
|
|
case PlaySimulationType.Accelerate:
|
|
GetPlayNormalCost(restPp, playPtn, situation, out playType);
|
|
if (playType != PlaySimulationType.Normal)
|
|
{
|
|
GetPlayAcceleratedCost(restPp, playPtn, situation, out playType);
|
|
}
|
|
break;
|
|
case PlaySimulationType.ChoiceTransform:
|
|
GetPlayChoiceTransformedCost(restPp, playPtn, null, out playType);
|
|
break;
|
|
case PlaySimulationType.Crystalize:
|
|
GetPlayNormalCost(restPp, playPtn, situation, out playType);
|
|
if (playType != PlaySimulationType.Normal)
|
|
{
|
|
GetPlayCrystalizedCost(restPp, out playType);
|
|
}
|
|
break;
|
|
case PlaySimulationType.Enhance:
|
|
GetPlayEnhancedCost(restPp, out playType);
|
|
break;
|
|
case PlaySimulationType.Normal:
|
|
GetPlayNormalCost(restPp, playPtn, situation, out playType);
|
|
break;
|
|
default:
|
|
AIConsoleUtility.LogError("IsPlayingSimulationType() : Check Target is Undefined Play Type!");
|
|
break;
|
|
}
|
|
return playType == checkPlayType;
|
|
}
|
|
|
|
public int GetPlaySimulationTypeCost(int restPp, List<int> playPtn, AISituationInfo situation, PlaySimulationType checkPlayType)
|
|
{
|
|
PlaySimulationType playType = PlaySimulationType.Undefined;
|
|
int result = -1;
|
|
switch (checkPlayType)
|
|
{
|
|
case PlaySimulationType.Accelerate:
|
|
result = GetPlayNormalCost(restPp, playPtn, situation, out playType);
|
|
if (playType != PlaySimulationType.Normal)
|
|
{
|
|
result = GetPlayAcceleratedCost(restPp, playPtn, situation, out playType);
|
|
}
|
|
break;
|
|
case PlaySimulationType.ChoiceTransform:
|
|
result = GetPlayChoiceTransformedCost(restPp, playPtn, null, out playType);
|
|
break;
|
|
case PlaySimulationType.Crystalize:
|
|
result = GetPlayNormalCost(restPp, playPtn, situation, out playType);
|
|
if (playType != PlaySimulationType.Normal)
|
|
{
|
|
result = GetPlayCrystalizedCost(restPp, out playType);
|
|
}
|
|
break;
|
|
case PlaySimulationType.Enhance:
|
|
result = GetPlayEnhancedCost(restPp, out playType);
|
|
break;
|
|
case PlaySimulationType.Normal:
|
|
result = GetPlayNormalCost(restPp, playPtn, situation, out playType);
|
|
break;
|
|
default:
|
|
AIConsoleUtility.LogError("GetPlaySimulationTypeCost() : Check Target is Undefined Play Type!");
|
|
break;
|
|
}
|
|
if (playType != checkPlayType)
|
|
{
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public int GetPlayNormalCost(int restPp, List<int> playPtn, AISituationInfo situation, out PlaySimulationType playType)
|
|
{
|
|
playType = PlaySimulationType.Undefined;
|
|
int num = Mathf.Max(0, Cost - this.GetCostBonus(playPtn, situation));
|
|
if (restPp >= num)
|
|
{
|
|
playType = PlaySimulationType.Normal;
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public int GetPlayEnhancedCost(int restPp, out PlaySimulationType playType)
|
|
{
|
|
playType = PlaySimulationType.Undefined;
|
|
int num = -1;
|
|
if (EnhanceCostList != null && EnhanceCostList.Count > 0)
|
|
{
|
|
for (int i = 0; i < EnhanceCostList.Count; i++)
|
|
{
|
|
int num2 = EnhanceCostList[i];
|
|
if (restPp >= num2 && num2 > num)
|
|
{
|
|
num = num2;
|
|
}
|
|
}
|
|
if (num >= 0)
|
|
{
|
|
playType = PlaySimulationType.Enhance;
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public int GetPlayChoiceTransformedCost(int restPp, List<int> playPtn, AISituationInfo situation, out PlaySimulationType playType)
|
|
{
|
|
playType = PlaySimulationType.Undefined;
|
|
int num = -1;
|
|
if (ChoiceTransformCostList != null && ChoiceTransformCostList.Count > 0)
|
|
{
|
|
for (int i = 0; i < ChoiceTransformCostList.Count; i++)
|
|
{
|
|
AIChoiceTransformCostInformation aIChoiceTransformCostInformation = ChoiceTransformCostList[i];
|
|
if (aIChoiceTransformCostInformation.CheckCondition(this, _field, playPtn, situation))
|
|
{
|
|
int num2 = (int)aIChoiceTransformCostInformation.Cost.EvalArg(this, playPtn, _field, situation);
|
|
if (restPp >= num2 && num2 > num)
|
|
{
|
|
num = num2;
|
|
}
|
|
}
|
|
}
|
|
if (num >= 0)
|
|
{
|
|
playType = PlaySimulationType.ChoiceTransform;
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public int GetPlayAcceleratedCost(int restPp, List<int> playPtn, AISituationInfo situation, out PlaySimulationType playType)
|
|
{
|
|
playType = PlaySimulationType.Undefined;
|
|
int num = -1;
|
|
if (AccelerateCostList != null && AccelerateCostList.Count > 0)
|
|
{
|
|
for (int i = 0; i < AccelerateCostList.Count; i++)
|
|
{
|
|
AIAccelerateInformation aIAccelerateInformation = AccelerateCostList[i];
|
|
if (aIAccelerateInformation.CheckCondition(this, _field, playPtn, situation))
|
|
{
|
|
int cost = aIAccelerateInformation.Cost;
|
|
if (restPp >= cost && cost > num)
|
|
{
|
|
num = cost;
|
|
}
|
|
}
|
|
}
|
|
if (num >= 0)
|
|
{
|
|
playType = PlaySimulationType.Accelerate;
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public int GetPlayCrystalizedCost(int restPp, out PlaySimulationType playType)
|
|
{
|
|
playType = PlaySimulationType.Undefined;
|
|
int num = -1;
|
|
if (CrystalizeCostList != null && CrystalizeCostList.Count > 0)
|
|
{
|
|
for (int i = 0; i < CrystalizeCostList.Count; i++)
|
|
{
|
|
AICrystalizeInformation aICrystalizeInformation = CrystalizeCostList[i];
|
|
if (restPp >= aICrystalizeInformation.Cost && aICrystalizeInformation.Cost > num)
|
|
{
|
|
num = aICrystalizeInformation.Cost;
|
|
}
|
|
}
|
|
if (num >= 0)
|
|
{
|
|
playType = PlaySimulationType.Crystalize;
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public void SetCurrentCost(int target_cost)
|
|
{
|
|
if (target_cost < 0)
|
|
{
|
|
AIConsoleUtility.LogError($"SetCurrentCost: Set ilegal values [{target_cost}]");
|
|
}
|
|
Cost = target_cost;
|
|
}
|
|
|
|
public void AddCurrentCost(int add_cost)
|
|
{
|
|
Cost = Mathf.Max(0, Cost + add_cost);
|
|
}
|
|
|
|
public void CreateHandPlayEstimator(AIParamQuery paramQuery, int handIndex, BattlePlayerPair sourcePair, EnemyAI ai)
|
|
{
|
|
_handPlayEstimator = new AIHandPlayEstimator(paramQuery, handIndex, this, sourcePair, ai);
|
|
}
|
|
|
|
public AIHandPlayEstimator GetHandPlayEstimator()
|
|
{
|
|
return _handPlayEstimator;
|
|
}
|
|
|
|
public int GetBaseSkillCount()
|
|
{
|
|
return BattleSkills.Count();
|
|
}
|
|
|
|
public bool IsHoldingBattleSkill(string hash)
|
|
{
|
|
if (BattleSkillHashList == null || BattleSkillHashList.Count <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
for (int i = 0; i < BattleSkillHashList.Count; i++)
|
|
{
|
|
if (hash == BattleSkillHashList[i].ToString())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void ResetParameterAfterPlayPtnEvaluation()
|
|
{
|
|
SpellboostCount = RealSpellboostCount;
|
|
Cost = RealCost;
|
|
if (_originalWhiteRitualCount != WhiteRitualCount)
|
|
{
|
|
if (IsDead && WhiteRitualCount <= 0 && _originalWhiteRitualCount > 0)
|
|
{
|
|
IsDead = false;
|
|
}
|
|
WhiteRitualCount = _originalWhiteRitualCount;
|
|
}
|
|
}
|
|
|
|
public void RollBackFromOneRecord(AIVirtualFieldRollBackRecord.CardParamRecord record)
|
|
{
|
|
Cost = record.Cost;
|
|
SpellboostCount = record.SpellBoost;
|
|
IsDead = record.IsDead;
|
|
WhiteRitualCount = record.WhiteRitualCount;
|
|
if (TagCollectionContainer.HasTagCollection(TagCollectionType.ActivateCount))
|
|
{
|
|
TagCollectionContainer.ActivateCountTags.UpdateCounterList(record.ActivateCounterList);
|
|
}
|
|
}
|
|
|
|
public void NotBeAttacked()
|
|
{
|
|
IsSkillCantUnderAnyAttack = true;
|
|
}
|
|
|
|
public float EvalKillerAttackValue(List<int> playPtn, AISituationInfo situation)
|
|
{
|
|
float num = (IsUnit ? (0f - this.EvaluateValueOnField(playPtn, situation, useStyle: true, doesUseLostLife: true, useOthersTag: true, useIgnoreInBattle: true) + this.EvaluateBreakValue(playPtn, useIgnoreBreak: true) + this.EvaluateLeaveValue(playPtn, useIgnoreInBattle: true)) : 0f);
|
|
float num2 = float.MinValue;
|
|
AIVirtualCard aIVirtualCard = null;
|
|
bool flag = _field.EnemyInplayCards.Any((AIVirtualCard card) => card.IsGuard);
|
|
for (int num3 = 0; num3 < _field.EnemyInplayCards.Count; num3++)
|
|
{
|
|
float num4 = 0f;
|
|
AIVirtualCard aIVirtualCard2 = _field.EnemyInplayCards[num3];
|
|
if (!aIVirtualCard2.IsUnit || aIVirtualCard2.IsCantUnderAnyAttack() || (flag && !aIVirtualCard2.IsGuard && !IsIgnoreGuard) || new AIVirtualAttackInfo(this, aIVirtualCard2).WillTargetDestroyByAttackTags(_field, playPtn, this))
|
|
{
|
|
continue;
|
|
}
|
|
bool flag2 = true;
|
|
if (aIVirtualCard2.IsIndependent || aIVirtualCard2.IsIndestructible)
|
|
{
|
|
int damage = BaseCard.DamageCalculationAtkTypeAttack.Damage;
|
|
if (aIVirtualCard2.BaseCard.CalculateFinalDamageAmount(damage) < aIVirtualCard2.Life)
|
|
{
|
|
flag2 = false;
|
|
}
|
|
}
|
|
if (flag2)
|
|
{
|
|
float num5 = aIVirtualCard2.EvaluateValueOnField(EnemyAI.EmptyPlayPtn, null, useStyle: true, doesUseLostLife: true, useOthersTag: true, useIgnoreInBattle: true) - aIVirtualCard2.EvaluateBreakValue(EnemyAI.EmptyPlayPtn, useIgnoreBreak: true) - aIVirtualCard2.EvaluateLeaveValue(EnemyAI.EmptyPlayPtn, useIgnoreInBattle: true);
|
|
num4 += num5;
|
|
}
|
|
int damage2 = aIVirtualCard2.BaseCard.DamageCalculationAtkTypeBeAttacked.Damage;
|
|
if (BaseCard.CalculateFinalDamageAmount(damage2) >= Life)
|
|
{
|
|
num4 += num;
|
|
}
|
|
if (num4 > num2)
|
|
{
|
|
num2 = num4;
|
|
aIVirtualCard = aIVirtualCard2;
|
|
}
|
|
}
|
|
if (aIVirtualCard != null)
|
|
{
|
|
return num2;
|
|
}
|
|
return 0f;
|
|
}
|
|
|
|
public void GiveRemoveByBanish()
|
|
{
|
|
_destroyByBanishCount++;
|
|
_bounceByBanishCount++;
|
|
}
|
|
|
|
public void DepriveRemoveByBanish()
|
|
{
|
|
if (_destroyByBanishCount > 0)
|
|
{
|
|
_destroyByBanishCount--;
|
|
}
|
|
if (_bounceByBanishCount > 0)
|
|
{
|
|
_bounceByBanishCount--;
|
|
}
|
|
}
|
|
|
|
public void GiveRemoveByDestroy()
|
|
{
|
|
_banishByDestroyCount++;
|
|
}
|
|
|
|
public void DepriveRemoveByDestroy()
|
|
{
|
|
if (_banishByDestroyCount > 0)
|
|
{
|
|
_banishByDestroyCount--;
|
|
}
|
|
}
|
|
|
|
public void AddUntouchableCount()
|
|
{
|
|
UntouchableCount++;
|
|
}
|
|
|
|
public void SubUntouchableCount()
|
|
{
|
|
UntouchableCount--;
|
|
if (UntouchableCount < 0)
|
|
{
|
|
UntouchableCount = 0;
|
|
}
|
|
}
|
|
|
|
public void RemoveCard(AISituationInfo situation, AIRemovalType type, bool isFromSkill)
|
|
{
|
|
switch (type)
|
|
{
|
|
case AIRemovalType.Destroy:
|
|
TryDestroyCard(situation, isFromSkill);
|
|
break;
|
|
case AIRemovalType.Banish:
|
|
TryBanishCard(situation);
|
|
break;
|
|
case AIRemovalType.Bounce:
|
|
TryBounceCard(situation);
|
|
break;
|
|
}
|
|
RemoveTempBuff();
|
|
}
|
|
|
|
private void TryDestroyCard(AISituationInfo situation, bool isFromSkill)
|
|
{
|
|
if (IsDestroyByBanish)
|
|
{
|
|
if (IsBanishByDestroy || this.IsRemoveByDestroy(EnemyAI.EmptyPlayPtn, situation))
|
|
{
|
|
Destroy(situation, isFromSkill);
|
|
}
|
|
else if (!isFromSkill || !IsIndestructible)
|
|
{
|
|
Banish(situation);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Destroy(situation, isFromSkill);
|
|
}
|
|
}
|
|
|
|
private void TryBanishCard(AISituationInfo situation)
|
|
{
|
|
if (IsBanishByDestroy || this.IsRemoveByDestroy(EnemyAI.EmptyPlayPtn, situation))
|
|
{
|
|
Destroy(situation, isFromSkill: true);
|
|
}
|
|
else
|
|
{
|
|
Banish(situation);
|
|
}
|
|
}
|
|
|
|
private void TryBounceCard(AISituationInfo situation)
|
|
{
|
|
if (IsBounceByBanish)
|
|
{
|
|
if (IsBanishByDestroy || this.IsRemoveByDestroy(EnemyAI.EmptyPlayPtn, situation))
|
|
{
|
|
if (IsIndestructible)
|
|
{
|
|
Bounce(situation);
|
|
}
|
|
else
|
|
{
|
|
Destroy(situation, isFromSkill: true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Banish(situation);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Bounce(situation);
|
|
}
|
|
}
|
|
|
|
public bool CreateOtherEvolveParameterFromBattleCardBase(EnemyAI ai, BattleCardBase origin, BattleCardBase baseParamCard, AISituationInfo situation)
|
|
{
|
|
if (origin == null)
|
|
{
|
|
AIConsoleUtility.LogError("CreateOtherEvolvedCardParam() error!! param origin card is null");
|
|
return false;
|
|
}
|
|
if (baseParamCard == null)
|
|
{
|
|
AIConsoleUtility.LogError("CreateOtherEvolvedCardParam() error!! new param card is null!");
|
|
return false;
|
|
}
|
|
if (OtherEvolveParameter != null)
|
|
{
|
|
AIConsoleUtility.LogError("SetOtherEvolvedCardParam() error!! exist param data already!");
|
|
return false;
|
|
}
|
|
OtherEvolveParameter = new AIVirtualCardParameter(origin, baseParamCard, BuffRecorderCollection);
|
|
AIAttachedTagCollection attachedTags = TagCollectionContainer.AttachedTags;
|
|
AIRemovedTagCollection removedTagCollection = TagCollectionContainer.RemovedTagCollection;
|
|
TagCollectionContainer.RemoveAllTagWithUpdatingFieldCardList(this, SelfField, situation);
|
|
InitializeTags(ai.ParamQuery, attachedTags, removedTagCollection);
|
|
return true;
|
|
}
|
|
|
|
public void SetOtherEvolveParameterFromVirtualCard(AIVirtualCard source)
|
|
{
|
|
if (source.OtherEvolveParameter != null)
|
|
{
|
|
OtherEvolveParameter = source.OtherEvolveParameter;
|
|
BaseParameter = source.BaseParameter;
|
|
}
|
|
}
|
|
|
|
public void SetOtherEvolveParameterFromBuildParameter(ReferableVirtualCardBuildParameterCollection buildParameter)
|
|
{
|
|
if (buildParameter.OtherEvolveCardParameter != null)
|
|
{
|
|
OtherEvolveParameter = buildParameter.OtherEvolveCardParameter;
|
|
BaseParameter = buildParameter.BaseParameter;
|
|
}
|
|
}
|
|
|
|
public void AddCannotAttackInformation(AICannotAttackInformation info)
|
|
{
|
|
_cannotAttackInfoList = AIParamQuery.AddElementToList(info, _cannotAttackInfoList);
|
|
}
|
|
|
|
public void CopyCannotAttackInfoList(AIVirtualCard sourceCard)
|
|
{
|
|
_cannotAttackInfoList = AIParamQuery.CloneList(sourceCard._cannotAttackInfoList);
|
|
}
|
|
|
|
public void RemoveCannotAttackInformation(AICannotAttackInformation info)
|
|
{
|
|
if (_cannotAttackInfoList == null || _cannotAttackInfoList.Count <= 0)
|
|
{
|
|
return;
|
|
}
|
|
for (int num = _cannotAttackInfoList.Count - 1; num >= 0; num--)
|
|
{
|
|
if (_cannotAttackInfoList[num].IsEqual(info))
|
|
{
|
|
_cannotAttackInfoList.RemoveAt(num);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsCannotAttackByTag(AIVirtualAttackInfo situation)
|
|
{
|
|
if (_cannotAttackInfoList == null || _cannotAttackInfoList.Count <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
for (int i = 0; i < _cannotAttackInfoList.Count; i++)
|
|
{
|
|
if (_cannotAttackInfoList[i].IsCannotAttack(_field, situation))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public virtual ulong GetHash()
|
|
{
|
|
if (IsDead && !IsLeader)
|
|
{
|
|
return 0uL;
|
|
}
|
|
ulong num = 0uL;
|
|
num += (ulong)((long)Attack * 6337L);
|
|
num += (ulong)((long)Life * 11383L);
|
|
num += (ulong)((long)DefLife * 173L);
|
|
num += (ulong)((long)EvolutionAttack * 1488017L);
|
|
num += (ulong)((long)EvolutionLife * 937477L);
|
|
num += (ulong)((long)Cost * 14401L);
|
|
num += PRIME_NUMBERS_FOR_CLAN[(int)Clan % PRIME_NUMBERS_FOR_CLAN.Length];
|
|
num += (ulong)((long)SpellboostCount * 8389L);
|
|
num += (ulong)((long)WhiteRitualCount * 3571L);
|
|
if (_tribeList != null)
|
|
{
|
|
for (int i = 0; i < _tribeList.Count; i++)
|
|
{
|
|
num += PRIME_NUMBERS_FOR_TRIBE[(int)_tribeList[i] % PRIME_NUMBERS_FOR_TRIBE.Length];
|
|
}
|
|
}
|
|
num += TagCollectionContainer.GetHash(this) * 5237;
|
|
bool flag = false;
|
|
if (!IsLeader && AIData != null)
|
|
{
|
|
flag = true;
|
|
}
|
|
if (FusionIngredients != null)
|
|
{
|
|
num += FusionIngredients.GetHash();
|
|
}
|
|
if (IsOnField)
|
|
{
|
|
num += (ulong)((long)AttackableCount * 557L);
|
|
num += (ulong)((long)ChantCount * 5683L);
|
|
num += (ulong)((long)ReferringSelfCount * 558869L);
|
|
num += BarrierInfoCollection.GetHash();
|
|
if (flag)
|
|
{
|
|
num += (ulong)((long)AIData.BattleBonusExpr.Hash * 761L);
|
|
}
|
|
if (IsAlly)
|
|
{
|
|
num += (ulong)(IsFirstTurn ? 191 : 19);
|
|
if (IsAttackable(EnemyAI.EmptyPlayPtn))
|
|
{
|
|
num = ((!AIAttackSimulationUtility.IsAttackPossible(_field, AttackLeaderSituation)) ? (num * 37) : (num * 151));
|
|
}
|
|
num *= 11;
|
|
}
|
|
num *= (ulong)(IsUnit ? 103 : 1);
|
|
num *= (ulong)(IsEvolution ? 59 : 1);
|
|
num *= (ulong)(IsGetOn ? 577 : 1);
|
|
num *= (ulong)(IsPreviousTurnAttacked ? 9749 : 1);
|
|
num *= (ulong)(IsCantAttackAll ? 8089 : 1);
|
|
num *= (ulong)(IsNotConsumeEp ? 3527 : 1);
|
|
num *= (ulong)(IsLastword ? 809 : 1);
|
|
num *= (ulong)(IsSneak ? 811 : 1);
|
|
num *= (ulong)(IsKiller ? 821 : 1);
|
|
num *= (ulong)(IsDrain ? 823 : 1);
|
|
num *= (ulong)(IsRush ? 827 : 1);
|
|
num *= (ulong)(IsQuick ? 829 : 1);
|
|
num *= (ulong)(IsDestroyWhenAttack ? 839 : 1);
|
|
num *= (ulong)(IsGuard ? 853 : 1);
|
|
num *= (ulong)(IsIgnoreGuard ? 857 : 1);
|
|
num *= (ulong)(IsUntouchable ? 859 : 1);
|
|
num *= (ulong)(IsForceTargeting ? 863 : 1);
|
|
num *= (ulong)(IsUnbanishable ? 877 : 1);
|
|
}
|
|
if (IsInHand && flag)
|
|
{
|
|
num += (ulong)((long)AIData.PlayBonusExpr.Hash * 12007L);
|
|
num += (ulong)((long)AIData.BattleBonusExpr.Hash * 761L);
|
|
num += (ulong)((long)AIData.PriorityExpr.Hash * 101L);
|
|
}
|
|
return num;
|
|
}
|
|
}
|