engine cleanup passes 4-7 + multi-instancing ambient rip
Squashes 146 commits from battle-engine-extraction. Net: 2,045 files changed, +11,896 / -158,687 lines. Ships engine passes 4-7 (dead-code cull, view-layer stub, receive-path shrink) plus the Phase-5 AsyncLocal ambient deletion that turns concurrent battles into a type-system property rather than a scope contract. ## What landed **Passes 4-7 (chunks 1-34):** Extended the Phase-4 const-false collapse into a cascading cull across the skill graph, view layer, and receive-path periphery. Six mode flags (IsWatchBattle/IsReplayBattle/IsAdmin/IsAdminWatch/IsPuzzleQuest/ IsAINetwork) became `const false`, every guarded block deleted. Field*.cs subclass ctors + BackGroundBase + ObjectChecker culled to no-ops. Mulligan family reworked to take a mgr param through IMulliganMgr.InitMulligan. Emotion/Recovery/Resource clusters null-stubbed. Prediction/OperationSimulator/ skill filters converted from static ambient reads to per-mgr reads via SkillPrm.ownerCard.SelfBattlePlayer.BattleMgr / ins.BattleMgr / this.BattleMgr. **Phase-5 ambient rip (chunks 35-47):** Deleted BattleAmbient / BattleAmbient- Context / TestBattleScope in full. Every per-battle mutable slot now lives on the mgr instance itself: mgr.InstanceIsForecast / InstanceIsRandomDraw / InstanceRecoveryInfo / InstanceViewerId / InstanceNetworkAgent / GameMgr BattleManagerBase.GetIns() returns null unconditionally; the residual static flags + 3 façades (Certification.ViewerId, Data.BattleRecoveryInfo, ToolboxGame.RealTimeNetworkAgent) are null-tolerant defaults kept for the handful of engine-internal readers that still reference their types. Zero BattleAmbient references anywhere in engine + node + tests. Added pre-seeded GameMgr ctor overload threaded through the mgr chain (BattleManagerBase → SingleBattleMgr / NetworkBattleManagerBase → NetworkStandard- BattleMgr → HeadlessBattleMgr / HeadlessNetworkBattleMgr). Fixtures build a GameMgr, seed it via HeadlessEngineEnv.SeedCharaIds/SeedNetUser, and pass it to the mgr's ctor — no ambient reach. Node side (SVSim.BattleNode/SessionBattleEngine): _ctx replaced with a plain GameMgr field; 34 `using var _ambient = BattleAmbient.Enter(_ctx)` scope wraps ripped from every accessor and mutator; EngineGlobalInit.WirePerSessionGameMgr takes GameMgr as a param and runs from SessionBattleEngine.SetupInternal BEFORE mgr construction. Test side: TestBattleScope deleted; 18 fixture [SetUp]s migrated to `HeadlessEngineEnv.EnsureProcessGlobals()`; MultiInstanceEngineTests rewritten around per-mgr construction (GetIns() → null is the pinned invariant). ## Regression fixes - **chunk-48** (MulliganCtrl): chunk-35's `= null` stubs on card lookups broke the live receive-driven Deal path (BattlePlayerBase.DrawCard NRE'd downstream of NetworkPlayerMulliganCtrl.StartMulliganVfx). Restored the three lookups via `_battlePlayer.BattleMgr.GetBattleCardIdx`. Engine tests were satisfied by the WireMulliganPhase seam; unit tests exposed the live-path gap. ## Ship state - SVSim.BattleEngine.Tests: 56/56 pass, 2 skip - SVSim.UnitTests: 1554/1554 pass (was 1523/31-fail before chunk 48) - Solution build: 0 source warnings (40 pre-existing NU1902 MessagePack CVEs in SVSim.EmulatedEntrypoint, unrelated) - Sequential PVP smoke: verified live (two back-to-back battles, no regression on cleanup/spinup) - Concurrent PVP smoke: verified live Adds tools/engine-port/ClosureAnalyzer/ — the Roslyn transitive-type-closure analyzer needed to make future cascade cleanup safe (per feedback memory "Engine cleanup needs closure tool" from the 2026-06-28 pass-3 failure). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -99,19 +99,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
{
|
||||
return (DeathTypeInformation)MemberwiseClone();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
WhenDestroy = false;
|
||||
DestroyedByKiller = false;
|
||||
ChantDestroy = false;
|
||||
MysteriesDestroy = false;
|
||||
BanishDestroy = false;
|
||||
BurialRite = false;
|
||||
UseFusionIngredient = false;
|
||||
UseFusionMetamorphoseIngredient = false;
|
||||
LeaveByGetOn = false;
|
||||
}
|
||||
}
|
||||
|
||||
public class ParameterChangeInformation
|
||||
@@ -455,18 +442,10 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
}
|
||||
}
|
||||
|
||||
private const string CONDITION_CHARGE_COUNT = "charge_count";
|
||||
|
||||
private const string TARGET_CONDITION_CHARGE_COUNT = "self.charge_count";
|
||||
|
||||
private const string ME_INPLAY_CLASS_COUNT = "{me.inplay.class.count}";
|
||||
|
||||
private BattleCardBase _finalMetamorphoseCard;
|
||||
|
||||
protected BuildInfo _buildInfo;
|
||||
|
||||
public List<BattleCardBase> ReplayNoConsumeEpBuffInfoNameList = new List<BattleCardBase>();
|
||||
|
||||
protected SkillCollectionBase _normalSkillCollection;
|
||||
|
||||
protected SkillCollectionBase _evolveSkillCollection;
|
||||
@@ -479,12 +458,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
private bool _isOndraw;
|
||||
|
||||
public const int NONE_COST = -1;
|
||||
|
||||
public const int DEFAULT_SKILL_ACTIVATED_COUNT = 1;
|
||||
|
||||
public const int DEFAULT_THIS_TURN_SKILL_ACTIVATED_COUNT = 0;
|
||||
|
||||
private int _skillActivatedCountWrapValue = -1;
|
||||
|
||||
private int _skillActivatedCount;
|
||||
@@ -551,23 +524,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
}
|
||||
}
|
||||
|
||||
public int MetamorphoseCount
|
||||
{
|
||||
get
|
||||
{
|
||||
int num = 0;
|
||||
BattleCardBase metamorphoseCard = MetamorphoseCard;
|
||||
while (metamorphoseCard != null)
|
||||
{
|
||||
metamorphoseCard = metamorphoseCard.MetamorphoseCard;
|
||||
num++;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
public BattleCardBase ReplayBuffInfoCard { get; set; }
|
||||
|
||||
public int PlayedTurn { get; protected set; }
|
||||
|
||||
public DeathTypeInformation DeathTypeInfo { get; protected set; }
|
||||
@@ -578,8 +534,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
public string UpdateBuildInfoBeforeCardName { get; private set; } = string.Empty;
|
||||
|
||||
public bool IsChoiceEvolutionCardBeforeUpdateBuildInfo => UpdateBuildInfoBeforeCardId / 1000000 == 910;
|
||||
|
||||
public List<SkillCreator.SkillBuildInfo> NormalSkillBuildInfos => _buildInfo.NormalSkillBuildInfos;
|
||||
|
||||
public List<SkillCreator.SkillBuildInfo> EvolveSkillBuildInfos => _buildInfo.EvolveSkillBuildInfos;
|
||||
@@ -599,12 +553,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
public List<BuffInfo> BuffInfoList { get; private set; }
|
||||
|
||||
public List<BuffInfo> ReplayBuffInfoList { get; set; } = new List<BuffInfo>();
|
||||
|
||||
public List<BuffInfo> ReplayAllCopyBuffInfoList { get; set; } = new List<BuffInfo>();
|
||||
|
||||
public List<NetworkBattleReceiver.ReplayBuffInfoLabel> ReplayBuffInfoLabelList { get; set; } = new List<NetworkBattleReceiver.ReplayBuffInfoLabel>();
|
||||
|
||||
protected CardInnerOptionsBase InnerOptions => _buildInfo.InnerOptions;
|
||||
|
||||
public IBattleResourceMgr ResourceMgr => _buildInfo.ResourceMgr;
|
||||
@@ -695,7 +643,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!GameMgr.GetIns().IsNewReplayBattle)
|
||||
if (!_buildInfo.BattleMgr.GameMgr.IsNewReplayBattle)
|
||||
{
|
||||
if (!SelfBattlePlayer.Class.IsCantAttackClass && !SkillApplyInformation.IsSkillCantAtkClass && !IsEvolDrunkenness)
|
||||
{
|
||||
@@ -713,22 +661,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
public bool IsCantAttackClassOnReplay { get; set; }
|
||||
|
||||
public bool IsCantAttackClassOnlyEvolDrunkenness
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!SelfBattlePlayer.Class.IsCantAttackClass && !SkillApplyInformation.IsSkillCantAtkClass && IsEvolDrunkenness)
|
||||
{
|
||||
if (IsFirstTurn && SkillApplyInformation.IsRush)
|
||||
{
|
||||
return SkillApplyInformation.IsQuick;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSummonDrunkenness { get; set; }
|
||||
|
||||
public bool IsPreviousTurnAttacked { get; set; }
|
||||
@@ -1015,7 +947,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!GameMgr.GetIns().IsNewReplayBattle)
|
||||
if (!_buildInfo.BattleMgr.GameMgr.IsNewReplayBattle)
|
||||
{
|
||||
if (AttackableCount <= 0 || (IsSummonDrunkenness && (!IsSummonDrunkenness || !IsEvolution)) || IsCantAttack)
|
||||
{
|
||||
@@ -1089,32 +1021,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
public int CardId => _buildInfo.CardId;
|
||||
|
||||
public int EquitedCardId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsChoiceEvolutionCard)
|
||||
{
|
||||
return BaseParameter.BaseCardId;
|
||||
}
|
||||
DataMgr.SpecialBattleSetting specialBattleSettingInfo = GameMgr.GetIns().GetDataMgr().SpecialBattleSettingInfo;
|
||||
if (specialBattleSettingInfo == null)
|
||||
{
|
||||
return CardId;
|
||||
}
|
||||
Dictionary<int, int> idOverridePairDict = specialBattleSettingInfo.IdOverridePairDict;
|
||||
if (idOverridePairDict == null)
|
||||
{
|
||||
return CardId;
|
||||
}
|
||||
if (idOverridePairDict.ContainsKey(CardId))
|
||||
{
|
||||
return idOverridePairDict[CardId];
|
||||
}
|
||||
return CardId;
|
||||
}
|
||||
}
|
||||
|
||||
public int Cost
|
||||
{
|
||||
get
|
||||
@@ -1164,8 +1070,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
public int MaxLife => SkillApplyInformation.GetMaxLife();
|
||||
|
||||
public int[] GenericValueArray => SkillApplyInformation.SkillGenericValueArray;
|
||||
|
||||
public virtual int BaseMaxLife
|
||||
{
|
||||
get
|
||||
@@ -1199,20 +1103,10 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
public DamageParam DamageCalculationAtkTypeBeAttacked => new DamageParam(SkillApplyInformation.IsAttackByLifeTypeBeAttacked ? Life : Atk, this, SkillFilterCreator.ContentKeyword.unit.ToString(), Clan);
|
||||
|
||||
public ICardVfxCreator VfxCreator { get; protected set; }
|
||||
|
||||
public bool AreCanPlayConditionsFulfilled => this.OnCheckCanPlay.GetAllFuncCallResults().All((bool condition) => condition);
|
||||
|
||||
public bool AreCanAttackConditionsFulfilled => this.OnCheckCanAttack.GetAllFuncCallResults().All((bool condition) => condition);
|
||||
|
||||
public bool AreCanBeAttackedConditionsFulfilled => this.OnCheckCanBeAttacked.GetAllFuncCallResults().All((bool condition) => condition);
|
||||
|
||||
public bool AreCanBeSelectedConditionsFulfilled => this.OnCheckCanBeSelected.GetAllFuncCallResults().All((bool condition) => condition);
|
||||
|
||||
public bool AreCanShowDetailConditionsFulfilled => this.OnCheckCanShowDetail.GetAllFuncCallResults().All((bool condition) => condition);
|
||||
|
||||
public bool AreCanEvolveConditionsFulfilled => this.OnCheckCanEvolve.GetAllFuncCallResults().All((bool condition) => condition);
|
||||
|
||||
public int FixedUseCost => CalcFixedUseCost(SelfBattlePlayer.Pp);
|
||||
|
||||
public List<int> UseCostList
|
||||
@@ -1336,10 +1230,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
public bool HasWhenFight => Skills.Any((SkillBase s) => s.IsWhenFightSkill);
|
||||
|
||||
public bool HasFusionSkill => Skills.Any((SkillBase s) => s is Skill_fusion);
|
||||
|
||||
public bool HasNoSelectFusionSkill => Skills.Any((SkillBase s) => s.IsNoSelectFusionSkill);
|
||||
|
||||
public bool IsChoiceBraveSkillCard { get; set; }
|
||||
|
||||
public bool HasSkillWhenEvolve => EvolutionSkills.Any((SkillBase s) => s.IsWhenEvolveSkill);
|
||||
@@ -1375,8 +1265,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsLegend => BaseParameter.Rarity >= 4;
|
||||
|
||||
public int DrawTurn { get; set; }
|
||||
|
||||
public bool IsHaveBurialRiteJudgeBothFlag
|
||||
@@ -1473,14 +1361,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
public event Func<bool> OnCheckCanAttack;
|
||||
|
||||
public event Func<bool> OnCheckCanBeAttacked;
|
||||
|
||||
public event Func<bool> OnCheckCanBeSelected;
|
||||
|
||||
public event Func<bool> OnCheckCanShowDetail;
|
||||
|
||||
public event Func<bool> OnCheckCanEvolve;
|
||||
|
||||
public void SetPlayedTurnNow()
|
||||
{
|
||||
PlayedTurn = SelfBattlePlayer.Turn;
|
||||
@@ -1527,19 +1407,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateChoiceEvolutionBeforeCard(int cardId, string cardName)
|
||||
{
|
||||
UpdateBuildInfoBeforeCardId = cardId;
|
||||
UpdateBuildInfoBeforeCardName = cardName;
|
||||
}
|
||||
|
||||
public void ResetReplayBuffInfo()
|
||||
{
|
||||
ReplayBuffInfoList.Clear();
|
||||
ReplayNoConsumeEpBuffInfoNameList.Clear();
|
||||
ReplayBuffInfoLabelList.Clear();
|
||||
}
|
||||
|
||||
public virtual string SkillDescription(BattlePlayerBase.SideLogInfo sideLogInfo = null, bool isSkipOption = false, BuffInfo buff = null, string divergenceId = "", List<int> skillDescriptionValueList = null, List<int> sideLogDescriptionValueList = null)
|
||||
{
|
||||
return ConvertSkillDescription(BaseParameter.SkillDescription, sideLogInfo, isSkipOption, buff, divergenceId, skillDescriptionValueList, (IsBuffDetail && sideLogInfo == null && ReplayBuffDetailSkillDescriptionValueList.Count > 0) ? ReplayBuffDetailSkillDescriptionValueList : ((sideLogDescriptionValueList != null) ? sideLogDescriptionValueList : ReplaySkillDescriptionValueList));
|
||||
@@ -1550,26 +1417,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
return ConvertSkillDescription(BaseParameter.EvoSkillDescription, sideLogInfo, isSkipOption, buff, divergenceId, skillDescriptionValueList, (IsBuffDetail && sideLogInfo == null && ReplayBuffDetailEvoSkillDescriptionValueList.Count > 0) ? ReplayBuffDetailEvoSkillDescriptionValueList : ((sideLogDescriptionValueList != null) ? sideLogDescriptionValueList : ReplayEvoSkillDescriptionValueList));
|
||||
}
|
||||
|
||||
public string CopiedSkillDescription(string skillDescription, List<int> skillDescriptionValueList)
|
||||
{
|
||||
return ConvertSkillDescription(skillDescription, null, isSkipOption: false, null, "", skillDescriptionValueList, null);
|
||||
}
|
||||
|
||||
public string CopiedEvoSkillDescription(string skillDescription, List<int> skillDescriptionValueList)
|
||||
{
|
||||
return ConvertSkillDescription(skillDescription, null, isSkipOption: false, null, "", skillDescriptionValueList, null);
|
||||
}
|
||||
|
||||
public string CopiedSkillDescriptionInReplay(BuffInfo buff, List<int> copiedSkillDescriptionValueList)
|
||||
{
|
||||
return ConvertSkillDescription(BaseParameter.SkillDescription, null, isSkipOption: false, buff, "", null, copiedSkillDescriptionValueList);
|
||||
}
|
||||
|
||||
public string CopiedEvoSkillDescriptionInReplay(BuffInfo buff, List<int> copiedEvoSkillDescriptionValueList)
|
||||
{
|
||||
return ConvertSkillDescription(BaseParameter.EvoSkillDescription, null, isSkipOption: false, buff, "", null, copiedEvoSkillDescriptionValueList);
|
||||
}
|
||||
|
||||
public virtual bool CantBeFocusedAttack(BattleCardBase attackCard)
|
||||
{
|
||||
if (SkillApplyInformation.IsSneak)
|
||||
@@ -1687,7 +1534,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!SelfBattlePlayer.IsPlayer && GameMgr.GetIns().IsAdminWatch)
|
||||
if (!SelfBattlePlayer.IsPlayer && _buildInfo.BattleMgr.GameMgr.IsAdminWatch)
|
||||
{
|
||||
if (isCheckOnDraw && IsOnDraw)
|
||||
{
|
||||
@@ -1853,7 +1700,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
public Action ForceAttackOff()
|
||||
{
|
||||
if (BattleManagerBase.GetIns().IsRecovery)
|
||||
if (_buildInfo.BattleMgr.IsRecovery)
|
||||
{
|
||||
return delegate
|
||||
{
|
||||
@@ -1881,47 +1728,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
return NormalSkills.Any((SkillBase s) => s.IsWhenPlaySkill);
|
||||
}
|
||||
|
||||
public int GetCurrentAtkBuff()
|
||||
{
|
||||
if (IsEvolution)
|
||||
{
|
||||
return SkillApplyInformation.GetAtk(ignoreLowerLimit: true) - BaseParameter.EvoAtk;
|
||||
}
|
||||
return SkillApplyInformation.GetAtk(ignoreLowerLimit: true) - BaseParameter.Atk;
|
||||
}
|
||||
|
||||
public int GetCurrentLifeBuff()
|
||||
{
|
||||
if (IsEvolution)
|
||||
{
|
||||
return SkillApplyInformation.GetMaxLife() - BaseParameter.EvoLife;
|
||||
}
|
||||
return SkillApplyInformation.GetMaxLife() - BaseParameter.Life;
|
||||
}
|
||||
|
||||
public bool IsMutationPlayPp(int pp)
|
||||
{
|
||||
int num = CalcFixedUseCost(pp, skipCondition: true);
|
||||
if (-1 != num && num <= pp)
|
||||
{
|
||||
return pp < Cost;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Skill_pp_fixeduse GetAccelerateOrCrystallizeSkill(int currentPp)
|
||||
{
|
||||
Skill_pp_fixeduse result = null;
|
||||
for (int i = 0; i < Skills.Count(); i++)
|
||||
{
|
||||
if (Skills.ElementAt(i) is Skill_pp_fixeduse skill_pp_fixeduse && skill_pp_fixeduse._fixedUsePP <= currentPp && skill_pp_fixeduse._fixedUsePP < Cost && currentPp < Cost)
|
||||
{
|
||||
result = skill_pp_fixeduse;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int CalcFixedUseCost(int currentPp, bool skipCondition = false)
|
||||
{
|
||||
int num = -1;
|
||||
@@ -1942,15 +1748,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
return num;
|
||||
}
|
||||
|
||||
public int GetPaidFixedCost()
|
||||
{
|
||||
if (ExecutedFixedUseCostIndex != -1 && Skills.ElementAt(ExecutedFixedUseCostIndex) is Skill_pp_fixeduse skill_pp_fixeduse)
|
||||
{
|
||||
return skill_pp_fixeduse._fixedUsePP;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public bool CheckConditionFixedUseCost(bool isPrePlay)
|
||||
{
|
||||
for (int i = 0; i < Skills.Count(); i++)
|
||||
@@ -2006,13 +1803,13 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
private CardParameter CreateClassParameter(bool isPlayer)
|
||||
{
|
||||
DataMgr dataMgr = GameMgr.GetIns().GetDataMgr();
|
||||
DataMgr dataMgr = _buildInfo.BattleMgr.GameMgr.GetDataMgr();
|
||||
return new CardParameter((CardBasePrm.ClanType)(isPlayer ? dataMgr.GetPlayerClassId() : dataMgr.GetEnemyClassId()));
|
||||
}
|
||||
|
||||
public void ChangeClassClanParameter()
|
||||
{
|
||||
DataMgr dataMgr = GameMgr.GetIns().GetDataMgr();
|
||||
DataMgr dataMgr = _buildInfo.BattleMgr.GameMgr.GetDataMgr();
|
||||
BaseParameter.ChangeClanParameter((CardBasePrm.ClanType)(IsPlayer ? dataMgr.GetPlayerClassId() : dataMgr.GetEnemyClassId()));
|
||||
}
|
||||
|
||||
@@ -2070,7 +1867,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
public virtual void Setup(bool createNullView = false, bool isRecreate = false)
|
||||
{
|
||||
BattleCardView = CreateView(CreateViewBuildInfo(_buildInfo), createNullView);
|
||||
VfxCreator = CreateVfxCreator(IsPlayer, BattleCardView, createNullView);
|
||||
if (!createNullView)
|
||||
{
|
||||
foreach (SkillBase normalSkill in NormalSkills)
|
||||
@@ -2084,7 +1880,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
}
|
||||
if (SkillApplyInformation == null)
|
||||
{
|
||||
SkillApplyInformation = CreateSkillApplyInformation(this, VfxCreator);
|
||||
SkillApplyInformation = CreateSkillApplyInformation(this);
|
||||
SkillApplyInformation.InitializeInformation();
|
||||
}
|
||||
if (!isRecreate)
|
||||
@@ -2096,13 +1892,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
BanishedInfo = new BanishInfo(-1, isSelfTurn: false, BanishInfo.BanishPlace.None);
|
||||
}
|
||||
|
||||
public void RecreateView(GameObject cardGameObject)
|
||||
{
|
||||
_buildInfo.GameObject = cardGameObject;
|
||||
Setup(createNullView: false, isRecreate: true);
|
||||
SkillApplyInformation.ReSetupVfxCreator(VfxCreator);
|
||||
}
|
||||
|
||||
protected virtual void InitSkillCollection()
|
||||
{
|
||||
_normalSkillCollection = CreateSkillCondition(_buildInfo.NormalSkillBuildInfos, _buildInfo.SelfBattlePlayer, _buildInfo.OpponentBattlePlayer, _buildInfo.ResourceMgr);
|
||||
@@ -2223,16 +2012,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
}
|
||||
}
|
||||
|
||||
public virtual VfxBase Draw(Vector3 Pos)
|
||||
{
|
||||
return VfxCreator.CreateDraw(Pos, IsLegend);
|
||||
}
|
||||
|
||||
public virtual VfxBase Moving(Vector3 Pos)
|
||||
{
|
||||
return VfxCreator.CreateMoving(Pos);
|
||||
}
|
||||
|
||||
protected virtual VfxBase StartPlayCard()
|
||||
{
|
||||
foreach (BattleCardBase handCard in SelfBattlePlayer.HandCardList)
|
||||
@@ -2243,7 +2022,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
handCard.BattleCardView.UpdateMovability();
|
||||
}
|
||||
}
|
||||
if (!GameMgr.GetIns().IsNewReplayBattle)
|
||||
if (!_buildInfo.BattleMgr.GameMgr.IsNewReplayBattle)
|
||||
{
|
||||
SelfBattlePlayer.CantPlayChoiceBrave = false;
|
||||
SelfBattlePlayer.BattleView.UpdateChoiceBraveButtonPulsateEffectAndSprite();
|
||||
@@ -2335,7 +2114,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
if (!SelfBattlePlayer.ClassAndInPlayCardList.Contains(this))
|
||||
{
|
||||
DeathTypeInfo.WhenDestroy = Skills._skillTimingInfo.IsWhenDestroy;
|
||||
VfxBase vfx = VfxCreator.CreateDestroy(DeathTypeInfo, SelfBattlePlayer);
|
||||
VfxBase vfx = NullVfx.GetInstance();
|
||||
sequentialVfxPlayer.Register(vfx);
|
||||
}
|
||||
sequentialVfxPlayer.Register(allFuncVfxResults);
|
||||
@@ -2357,7 +2136,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
VfxBase allFuncVfxResults = this.OnDestroy.GetAllFuncVfxResults(this, skillProcessor);
|
||||
if (!SelfBattlePlayer.HandCardList.Contains(this))
|
||||
{
|
||||
VfxBase vfx = VfxCreator.CreateDestroyHand(DeathTypeInfo, SelfBattlePlayer);
|
||||
VfxBase vfx = NullVfx.GetInstance();
|
||||
BattleCardView.HideCanPlayEffect();
|
||||
sequentialVfxPlayer.Register(vfx);
|
||||
}
|
||||
@@ -2390,7 +2169,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
sequentialVfxPlayer.Register(this.OnBanish.GetAllFuncVfxResults(this, skillProcessor));
|
||||
if (!isReturn)
|
||||
{
|
||||
sequentialVfxPlayer.Register(VfxCreator.CreateBanish(DeathTypeInfo, SelfBattlePlayer));
|
||||
sequentialVfxPlayer.Register(NullVfx.GetInstance());
|
||||
}
|
||||
return sequentialVfxPlayer;
|
||||
}
|
||||
@@ -2400,7 +2179,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
VfxWithLoadingSequential vfxWithLoadingSequential = VfxWithLoadingSequential.Create(this.OnBanish.GetAllFuncVfxResults(this, skillProcessor));
|
||||
if (!SelfBattlePlayer.HandCardList.Contains(this))
|
||||
{
|
||||
vfxWithLoadingSequential.RegisterVfxWithLoading(VfxCreator.CreateBanishHand(DeathTypeInfo, SelfBattlePlayer));
|
||||
vfxWithLoadingSequential.RegisterVfxWithLoading(NullVfxWithLoading.GetInstance());
|
||||
}
|
||||
return vfxWithLoadingSequential;
|
||||
}
|
||||
@@ -2414,7 +2193,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
{
|
||||
SequentialVfxPlayer sequentialVfxPlayer = SequentialVfxPlayer.Create();
|
||||
sequentialVfxPlayer.Register(this.OnGetOn.GetAllFuncVfxResults(this, skillProcessor));
|
||||
sequentialVfxPlayer.Register(VfxCreator.CreateGeton(vehicleCardTrans, vehicleCardView, DeathTypeInfo, SelfBattlePlayer));
|
||||
sequentialVfxPlayer.Register(NullVfx.GetInstance());
|
||||
return sequentialVfxPlayer;
|
||||
}
|
||||
|
||||
@@ -2425,7 +2204,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
sequentialVfxPlayer.Register(SkillApplyInformation.AllSkillEffectStop());
|
||||
sequentialVfxPlayer.Register(RemoveFromInPlay());
|
||||
sequentialVfxPlayer.Register(SelfBattlePlayer.UniteCard(this, skillProcessor, skill));
|
||||
sequentialVfxPlayer.Register(VfxCreator.CreateBanish(DeathTypeInfo, SelfBattlePlayer));
|
||||
sequentialVfxPlayer.Register(NullVfx.GetInstance());
|
||||
return sequentialVfxPlayer;
|
||||
}
|
||||
|
||||
@@ -2436,7 +2215,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
DeathTypeInfo.UseFusionIngredient = true;
|
||||
DeathTypeInfo.UseFusionMetamorphoseIngredient = isFusionMetamorphose;
|
||||
VfxWithLoadingSequential vfxWithLoadingSequential = VfxWithLoadingSequential.Create(this.OnBanish.GetAllFuncVfxResults(this, skillProcessor));
|
||||
vfxWithLoadingSequential.RegisterVfxWithLoading(VfxCreator.CreateFusionHand(SelfBattlePlayer, fusionCard.BattleCardView, isFusionMetamorphose));
|
||||
vfxWithLoadingSequential.RegisterVfxWithLoading(NullVfxWithLoading.GetInstance());
|
||||
return vfxWithLoadingSequential;
|
||||
}
|
||||
|
||||
@@ -2460,12 +2239,12 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
public VfxBase StartHandEffect()
|
||||
{
|
||||
if (SelfBattlePlayer.IsPlayer || GameMgr.GetIns().IsAdminWatch)
|
||||
if (SelfBattlePlayer.IsPlayer || _buildInfo.BattleMgr.GameMgr.IsAdminWatch)
|
||||
{
|
||||
SequentialVfxPlayer sequentialVfxPlayer = SequentialVfxPlayer.Create();
|
||||
if (SpellChargeCount > 0 && HasSpellCharge && IsInHand)
|
||||
{
|
||||
sequentialVfxPlayer.Register(new HandEffectLoopStartVfx(BattleCardView, () => IsActionCard, HandEffectLoopStartVfx.HandEffectType.SpellCharge));
|
||||
sequentialVfxPlayer.Register(NullVfx.GetInstance());
|
||||
}
|
||||
return sequentialVfxPlayer;
|
||||
}
|
||||
@@ -2483,7 +2262,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
public virtual VfxBase StopSpellCharge()
|
||||
{
|
||||
return new HandEffectLoopEndVfx(BattleCardView);
|
||||
return NullVfx.GetInstance();
|
||||
}
|
||||
|
||||
public virtual VfxBase CreateMoveToHandVfx()
|
||||
@@ -2500,7 +2279,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
if (PlayerPrefsWrapper.GetBool(PlayerPrefsWrapper.SHOW_SIDE_LOG))
|
||||
{
|
||||
BattlePlayerBase.SideLogInfo sideLogInfo = new BattlePlayerBase.SideLogInfo(skill);
|
||||
return new ShowSideLogVfx(this, skill, SelfBattlePlayer.BattleView.GetSideLogControl(isSkillTargetSelect: false), (SkillDescription == string.Empty) ? GetCardSkillDescription(sideLogInfo, isEvolve) : SkillDescription, time, isEvol: false, sideLogInfo);
|
||||
return NullVfx.GetInstance();
|
||||
}
|
||||
return NullVfx.GetInstance();
|
||||
}
|
||||
@@ -2524,7 +2303,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
{
|
||||
SkillCollectionBase skillCollectionBase = (isEvolve ? EvolutionSkills : Skills);
|
||||
NetworkBattleManagerBase networkBattleManagerBase = SelfBattlePlayer.BattleMgr as NetworkBattleManagerBase;
|
||||
GameMgr ins = GameMgr.GetIns();
|
||||
GameMgr ins = _buildInfo.BattleMgr.GameMgr;
|
||||
if (!ins.IsAdminWatch && !ins.IsAINetwork && networkBattleManagerBase != null)
|
||||
{
|
||||
NetworkBattleReceiver.ReceiveData receiveData = networkBattleManagerBase.networkBattleData.GetReceiveData();
|
||||
@@ -2720,7 +2499,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
public VfxBase CreateMaskCardInPlayVfx()
|
||||
{
|
||||
return VfxCreator.CreateMaskCardInPlay();
|
||||
return NullVfx.GetInstance();
|
||||
}
|
||||
|
||||
public void AddCostModifier(ICardCostModifier modifier, SkillBase skill, bool eventCall = true)
|
||||
@@ -3042,23 +2821,9 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
return ParallelVfxPlayer.Create(parallelVfxPlayer, parallelVfxPlayer2);
|
||||
}
|
||||
|
||||
protected virtual ICardVfxCreator CreateVfxCreator(bool isPlayer, IBattleCardView battleCardView, bool isNullView)
|
||||
protected virtual ISkillApplyInformation CreateSkillApplyInformation(BattleCardBase card)
|
||||
{
|
||||
if (isNullView)
|
||||
{
|
||||
return NullCardVfxCreator.GetInstance();
|
||||
}
|
||||
return new CardVfxCreatorBase(isPlayer, this, battleCardView, _buildInfo.ResourceMgr);
|
||||
}
|
||||
|
||||
protected virtual ISkillApplyInformation CreateSkillApplyInformation(BattleCardBase card, ICardVfxCreator vfxCreator)
|
||||
{
|
||||
return new SkillApplyInformation(card, vfxCreator);
|
||||
}
|
||||
|
||||
public ParameterChangeInformation CreateParameterChangeInfo()
|
||||
{
|
||||
return new ParameterChangeInformation(Atk, BaseAtk, Life, MaxLife, BaseMaxLife);
|
||||
return new SkillApplyInformation(card);
|
||||
}
|
||||
|
||||
public void AddBuffInfo(BuffInfo buffInfo)
|
||||
@@ -3085,11 +2850,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
BuffInfoList.RemoveAll(condition);
|
||||
}
|
||||
|
||||
public bool IsContainBuffInfo(BuffInfo buffInfo)
|
||||
{
|
||||
return BuffInfoList.Contains(buffInfo);
|
||||
}
|
||||
|
||||
public void ClearBuffInfo()
|
||||
{
|
||||
BuffInfoList.Clear();
|
||||
@@ -3170,7 +2930,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
if ((handCardFrameEffectType < handCardFrameEffectType2 || (handCardFrameEffectType == HandCardFrameEffectType.LIGHT_BLUE && skill is Skill_pp_fixeduse)) && skill.VisualCheckCondition(pair, option, isPrePlay: true) && skill.PreprocessList.All((SkillPreprocessBase p) => p.IsRight(pair, option)))
|
||||
{
|
||||
handCardFrameEffectType = handCardFrameEffectType2;
|
||||
if ((GameMgr.GetIns().IsWatchBattle || isNewReplayRecord) && handCardFrameEffectType == HandCardFrameEffectType.YELLOW && (skill.ConditionTargetFilter is SkillTargetDeckFilter || skill.ConditionFilterCollection.VariableCompareFilter.Any((SkillVariableComareFilter c) => c.Text.Contains("deck") && RegisterSkillConditionCheck.IsSkillConditionCheck(skill))))
|
||||
if ((_buildInfo.BattleMgr.GameMgr.IsWatchBattle || isNewReplayRecord) && handCardFrameEffectType == HandCardFrameEffectType.YELLOW && (skill.ConditionTargetFilter is SkillTargetDeckFilter || skill.ConditionFilterCollection.VariableCompareFilter.Any((SkillVariableComareFilter c) => c.Text.Contains("deck") && RegisterSkillConditionCheck.IsSkillConditionCheck(skill))))
|
||||
{
|
||||
handCardFrameEffectType = HandCardFrameEffectType.NONE;
|
||||
}
|
||||
@@ -3187,7 +2947,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
bool isRobBuff = buff != null && buff.IsCopied;
|
||||
string text2 = (text.Contains("<<${") ? GetSkillDescriptionVariables(text) : text);
|
||||
bool flag = IsInHand || (text2.Contains("{me.inplay.class.count}") && (text2.Contains(SkillFilterCreator.ContentKeyword.hand.ToString()) || text2.Contains(SkillFilterCreator.ContentKeyword.deck.ToString())));
|
||||
if (num && !isSkipOption && !IsPlayer && !GameMgr.GetIns().IsAdminWatch && flag)
|
||||
if (num && !isSkipOption && !IsPlayer && !_buildInfo.BattleMgr.GameMgr.IsAdminWatch && flag)
|
||||
{
|
||||
isSkipOption = true;
|
||||
}
|
||||
@@ -3350,7 +3110,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
bool isSkillDescriptionExpressionValueDefault = !flag2;
|
||||
if (flag)
|
||||
{
|
||||
isSkillDescriptionExpressionValueDefault = ((flag3 || !GameMgr.GetIns().IsNewReplayBattle || text2.Contains("(divergence_id=")) ? EvalExpressionAndCondition(isSkillDescriptionExpressionValueDefault, text2, flag2, flag3, divergenceId, action, dictionary) : (replaySkillDescriptionValueList[num - 1] == 1));
|
||||
isSkillDescriptionExpressionValueDefault = ((flag3 || true /* headless: IsNewReplayBattle is const-false, guard collapses */ || text2.Contains("(divergence_id=")) ? EvalExpressionAndCondition(isSkillDescriptionExpressionValueDefault, text2, flag2, flag3, divergenceId, action, dictionary) : (replaySkillDescriptionValueList[num - 1] == 1));
|
||||
string empty = string.Empty;
|
||||
empty = ((!isSkillDescriptionExpressionValueDefault) ? list2[2] : list2[1]);
|
||||
valueList?.Add(isSkillDescriptionExpressionValueDefault ? 1 : 0);
|
||||
@@ -3380,13 +3140,13 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
if (Regex.Match(text, "{<<([^>])+>>@").Success)
|
||||
{
|
||||
text = text5 + list.Count + text6;
|
||||
int item = ((flag3 || !GameMgr.GetIns().IsNewReplayBattle) ? skillOptionValue.GetInt(SkillFilterCreator.ContentKeyword.v) : replaySkillDescriptionValueList[num - 1]);
|
||||
int item = ((flag3 || true /* headless: IsNewReplayBattle is const-false, guard collapses */) ? skillOptionValue.GetInt(SkillFilterCreator.ContentKeyword.v) : replaySkillDescriptionValueList[num - 1]);
|
||||
list.Add(item.ToString());
|
||||
valueList?.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
int item2 = ((flag3 || !GameMgr.GetIns().IsNewReplayBattle) ? skillOptionValue.GetInt(SkillFilterCreator.ContentKeyword.v) : replaySkillDescriptionValueList[num - 1]);
|
||||
int item2 = ((flag3 || true /* headless: IsNewReplayBattle is const-false, guard collapses */) ? skillOptionValue.GetInt(SkillFilterCreator.ContentKeyword.v) : replaySkillDescriptionValueList[num - 1]);
|
||||
text = text5 + item2 + text6;
|
||||
valueList?.Add(item2);
|
||||
}
|
||||
@@ -3592,8 +3352,8 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
public virtual VfxBase RecoveryInPlay(int inPlayIndex, bool newReplayMoveTurn = false)
|
||||
{
|
||||
SequentialVfxPlayer sequentialVfxPlayer = SequentialVfxPlayer.Create();
|
||||
sequentialVfxPlayer.Register(new SummonCardPreperationVfx(this));
|
||||
sequentialVfxPlayer.Register(new ChangeInPlayViewVfx(BattleCardView));
|
||||
sequentialVfxPlayer.Register(NullVfx.GetInstance());
|
||||
sequentialVfxPlayer.Register(NullVfx.GetInstance());
|
||||
sequentialVfxPlayer.Register(CreateMaskCardInPlayVfx());
|
||||
sequentialVfxPlayer.Register(InstantVfx.Create(delegate
|
||||
{
|
||||
@@ -3715,11 +3475,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
public VfxBase GetSpellChargeLoopEffect(int num)
|
||||
{
|
||||
Func<bool> getIsActionCard = () => IsActionCard || IsInplay || BattleCardView._hasCardEnteredPlayQueue;
|
||||
if (SpellChargeCount == 0 && num > 0)
|
||||
{
|
||||
return new HandEffectLoopStartVfx(BattleCardView, getIsActionCard, HandEffectLoopStartVfx.HandEffectType.SpellCharge);
|
||||
}
|
||||
return NullVfx.GetInstance();
|
||||
}
|
||||
|
||||
@@ -3754,11 +3509,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
BattleCardView.UpdateCostViewStrategy(isForceUpdate);
|
||||
}
|
||||
|
||||
public void InitHandParameterIconPos(HandParameter.IconLayout layout)
|
||||
{
|
||||
BattleCardView.InitHandParameterIconPos(layout);
|
||||
}
|
||||
|
||||
public IEnumerable<BattleCardBase> AsIEnumerable()
|
||||
{
|
||||
yield return this;
|
||||
@@ -3778,7 +3528,7 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!GameMgr.GetIns().IsAdmin && !IsPlayer && IsInHand)
|
||||
if (!_buildInfo.BattleMgr.GameMgr.IsAdmin && !IsPlayer && IsInHand)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -3809,20 +3559,13 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
|
||||
public int GetBurialRiteCount(BattlePlayerReadOnlyInfoPair playerInfoPair, SkillConditionCheckerOption option, bool isPrePlay)
|
||||
{
|
||||
if (BattleManagerBase.GetIns().BattlePlayer.PlayerBattleView._isEvolutionSkillSelect)
|
||||
if (_buildInfo.BattleMgr.BattlePlayer.PlayerBattleView._isEvolutionSkillSelect)
|
||||
{
|
||||
return EvolutionSkills.Count((SkillBase s) => s.CheckConditionWithoutBurialRite(playerInfoPair, option, isPrePlay));
|
||||
}
|
||||
return Skills.Count((SkillBase s) => s.CheckConditionWithoutBurialRite(playerInfoPair, option, isPrePlay));
|
||||
}
|
||||
|
||||
public void ReplaceParameterAndSkillOnDeck(int id)
|
||||
{
|
||||
_buildInfo.CardId = id;
|
||||
CreateParameter();
|
||||
InitSkillApplyInformationOnWhenReturn();
|
||||
}
|
||||
|
||||
public bool HasInductionSkill()
|
||||
{
|
||||
for (int i = 0; i < Skills.Count(); i++)
|
||||
@@ -3849,18 +3592,6 @@ public abstract class BattleCardBase : IReadOnlyBattleCardInfo, IBattleCardUniqu
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetInductionLabelNumber()
|
||||
{
|
||||
SkillBase skillBase = Skills.FirstOrDefault((SkillBase s) => s.IsInductionSkill && s.SkillPrm.buildInfo._icon != "induction" && s.SkillPrm.buildInfo._icon.Contains("induction"));
|
||||
if (skillBase == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
SkillOptionValue skillOptionValue = new SkillOptionValue(skillBase.SkillPrm.buildInfo._icon);
|
||||
skillOptionValue.SetupFilterVariable(BattleManagerBase.GetIns().GetBattlePlayerInfoPair(IsPlayer), this, isPrePlay: false, null);
|
||||
return skillOptionValue.GetInt(SkillFilterCreator.ContentKeyword.induction);
|
||||
}
|
||||
|
||||
public bool HasStackWhiteRitualAndOtherIconSkill()
|
||||
{
|
||||
if (HasSkillStackWhiteRitual)
|
||||
|
||||
Reference in New Issue
Block a user