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.
157 lines
5.1 KiB
C#
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;
|
|
}
|
|
}
|