Files
SVSimServer/SVSim.BattleEngine/Engine/Wizard/AIAttackSimulationUtility.cs
gamer147 957af3d1ec feat(battle-engine): full Unity/VFX/god-object shims + expanded copy closure (2570 files)
Authored Unity primitive/object-model shim, VFX layer (control-flow-preserving, InstantVfx never invokes its action -- headless suppression), god-object stubs (GameMgr/EffectMgr/UIManager with faithfully-extracted nested enums), View/UI/Touch tree, LitJson+BetterList+Tuple copied, third-party stubs. Discovered Roslyn header-error masking: fixing class-header type errors unmasks body references, so the true copy closure is ~2570 files (was 782 under masking). Errors: masked-25720 -> 268; our shim files compile clean. Remaining: ~50 residual shim/external types, 24 NGUI UI-base overrides, static-type fixes, plus likely 1-2 more unmask waves.
2026-06-05 17:22:20 -04:00

157 lines
5.1 KiB
C#

using System.Collections.Generic;
namespace Wizard;
public static class AIAttackSimulationUtility
{
public static bool IsUsePreCheckBuff(AIPlayTag tag, AIVirtualAttackInfo situation)
{
if (!situation.IsUsePreCheck || tag.Type != AIPlayTagType.AttackBuff)
{
return false;
}
AIAttackPreCheckInformation preCheckInformation = situation.PreCheckInformation;
if (preCheckInformation.HasBuffInfo)
{
return preCheckInformation.HasPreCheckBuffInfo(tag);
}
return false;
}
public static void SimulateAttackIfValuable(AIVirtualAttackInfo situation, AIVirtualField field, bool useAttackLeaderPreCheck, ref bool isAttackerUsed)
{
AIVirtualCard actor = situation.Actor;
AIVirtualCard attackTarget = situation.AttackTarget;
situation.IsAttackSuccessed = false;
AIVirtualCard allyClass = field.AllyClass;
int attackDamageToCertainCard = AIAttackTagSimulator.GetAttackDamageToCertainCard(field, situation, allyClass);
if (field.AllyClass.SimulateDamageAmount(attackDamageToCertainCard, isSkillDamage: true) >= allyClass.Life)
{
isAttackerUsed = true;
return;
}
if (AIDiscardUtility.CheckAttackDiscardTargetInPlayPtn(actor.SelfField, field.BestPlayPtn, situation))
{
isAttackerUsed = true;
return;
}
if (attackTarget.IsLeader)
{
int attackDamageToCertainCard2 = AIAttackTagSimulator.GetAttackDamageToCertainCard(field, situation, actor);
AISimulationBuffInfoCollection buffInfoListWhenCertainAttack = AIAttackTagSimulator.GetBuffInfoListWhenCertainAttack(field, situation);
float attackBonus = actor.GetAttackBonus(field.BestPlayPtn, situation);
AISimulationBuffInfo buffInfo = buffInfoListWhenCertainAttack?.GetBuffInfoToCertainCard(actor);
if (useAttackLeaderPreCheck && !IsExecuteAttackValuable(field, actor, actor.Attack, actor.Life, attackDamageToCertainCard2, buffInfo, attackBonus))
{
isAttackerUsed = true;
return;
}
AIAttackPreCheckInformation preCheckInformation = new AIAttackPreCheckInformation(attackBonus, buffInfoListWhenCertainAttack);
situation.SetPreCheckInformation(preCheckInformation);
}
AIVirtualAttackSimulator.Attack(situation, field);
if (actor.IsDead || !actor.IsAttackable(EnemyAI.EmptyPlayPtn))
{
isAttackerUsed = true;
}
if (!field.CardListSet.HasAttackableClassHolder)
{
return;
}
for (int i = 0; i < field.CardListSet.AttackableClassHolders.Count; i++)
{
AIVirtualCard aIVirtualCard = field.CardListSet.AttackableClassHolders[i];
if (aIVirtualCard.IsUnit && !aIVirtualCard.IsDead)
{
aIVirtualCard.TagCollectionContainer.AttackableClassTags.ChangeAttackableClassStatus(aIVirtualCard, field, field.BestPlayPtn);
}
}
}
public static bool IsAttackPossible(AIVirtualField field, AIVirtualAttackInfo attackSituation, List<AIVirtualCard> replacedEnemyInplayCards = null)
{
if (attackSituation == null || attackSituation.ActionType != AIOperationType.ATTACK)
{
return false;
}
AIVirtualCard actor = attackSituation.Actor;
AIVirtualCard attackTarget = attackSituation.AttackTarget;
if (actor.IsDead || attackTarget.IsDead || !actor.IsAttackable(EnemyAI.EmptyPlayPtn))
{
return false;
}
bool flag = attackTarget == field.EnemyClass;
if (actor.IsSkillCantAttackUnit)
{
if (flag)
{
return !actor.IsCantAttackClass();
}
return false;
}
if (flag && actor.IsCantAttackClass())
{
return false;
}
if (!(actor.IsAlly ? field.AllyInplayCards : field.EnemyInplayCards).Contains(actor))
{
return false;
}
if (attackTarget.IsAmulet || attackTarget.IsCantUnderAttack(field.ParamQuery, actor, null, field))
{
return false;
}
if (actor.IsCannotAttackByTag(attackSituation))
{
return false;
}
List<AIVirtualCard> list = ((!actor.IsAlly) ? field.AllyInplayCards : ((replacedEnemyInplayCards == null) ? field.EnemyInplayCards : replacedEnemyInplayCards));
bool flag2 = false;
if (list != null)
{
for (int i = 0; i < list.Count; i++)
{
AIVirtualCard aIVirtualCard = list[i];
if (aIVirtualCard.IsGuard && !aIVirtualCard.IsDead && !aIVirtualCard.IsCantUnderAttack(field.ParamQuery, actor, null, field))
{
flag2 = true;
break;
}
}
}
bool isGuard = attackTarget.IsGuard;
if (flag2 && !actor.IsIgnoreGuard && !isGuard)
{
return false;
}
if (!flag && actor.IsSkillCantAtkUnitNotHasGuard && !isGuard)
{
return false;
}
return true;
}
public static bool IsExecuteAttackValuable(AIVirtualField field, AIVirtualCard attacker, int attack, int life, int preDamage, AISimulationBuffInfo buffInfo, float attackBonus)
{
int num = attack;
int num2 = life;
num2 -= preDamage;
if (buffInfo != null)
{
num += buffInfo.TotalAttackBuff;
num2 += buffInfo.TotalLifeBuff;
}
if (num2 > 0 && num > 0)
{
return true;
}
float num3 = attackBonus;
if (num2 <= 0)
{
float num4 = attacker.EvaluateBreakValue(field.BestPlayPtn, useIgnoreBreak: true) + attacker.EvaluateLeaveValue(field.BestPlayPtn, useIgnoreInBattle: true);
num3 += num4 - attacker.Value;
}
return num3 > 0f;
}
}