Files
SVSimServer/SVSim.BattleEngine/Engine/Wizard/AIVirtualAttackSimulator.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

152 lines
5.6 KiB
C#

using System.Collections.Generic;
namespace Wizard;
public static class AIVirtualAttackSimulator
{
public static void Attack(AIVirtualAttackInfo situation, AIVirtualField field)
{
situation.IsAttackSuccessed = false;
if (situation.ActionType == AIOperationType.ATTACK && AIAttackSimulationUtility.IsAttackPossible(field, situation))
{
AIVirtualCard actor = situation.Actor;
_ = situation.AttackTarget;
actor.AttackableCount--;
field.ActionLength++;
situation.IsAttackSuccessed = true;
field.ApplyAttackBonus(situation);
field.ApplyClashBonus(situation);
AIPreprocessSimulationUtility.SimulatePreprocess(actor, situation, field, AIScriptTokenArgType.WHEN_ATTACK, isPseudo: false);
SimulateSkillsBeforeAttackCalculation(situation, field);
field.AllActivateCountHolderIncrement(situation, AIPlayTagType.AttackActivateCount, actor);
situation.ProcessCollection.CombinePreprocessToProcessQueue();
situation.ExecuteAllSkillProcess();
if (field.AllyClass.Life > 0 && field.EnemyClass.Life > 0)
{
ApplyAttackActionToTargetAndAttacker(situation, field);
}
}
}
private static void ApplyAttackActionToTargetAndAttacker(AIVirtualAttackInfo situation, AIVirtualField field)
{
if (situation.AttackTarget.IsLeader)
{
AttackLeaderDamageCalculation(situation, field);
}
else
{
AttackFollowerDamageCalculation(situation, field);
}
}
private static void AttackFollowerDamageCalculation(AIVirtualAttackInfo situation, AIVirtualField field)
{
AIVirtualCard actor = situation.Actor;
AIVirtualCard attackTarget = situation.AttackTarget;
_ = field.BestPlayPtn;
if (!actor.IsDead && !attackTarget.IsDead)
{
int attackerAtk = actor.Attack;
int targetAtk = attackTarget.Attack;
AIAttackTagSimulator.ExecuteAttackByLife(field, actor, attackTarget, ref attackerAtk, ref targetAtk);
attackerAtk = actor.SimulateAttackAmount(situation);
targetAtk = attackTarget.SimulateAttackAmount(situation);
int attackDamage = attackTarget.AddDamage(situation, attackerAtk, isSkillDamage: false);
int defendDamage = actor.AddDamage(situation, targetAtk, isSkillDamage: false);
situation.ExecuteAllSkillProcess();
if (attackTarget.IsDead)
{
attackTarget.RemoveCard(situation, AIRemovalType.Destroy, isFromSkill: false);
}
if (actor.IsDead)
{
actor.RemoveCard(situation, AIRemovalType.Destroy, isFromSkill: false);
}
ExecAfterClashSkills(situation, field, attackDamage, defendDamage);
situation.ExecuteAllSkillProcess();
}
}
private static void AttackLeaderDamageCalculation(AIVirtualAttackInfo situation, AIVirtualField field)
{
AIVirtualCard actor = situation.Actor;
AIVirtualCard attackTarget = situation.AttackTarget;
List<int> bestPlayPtn = field.BestPlayPtn;
if (actor.Life <= 0)
{
return;
}
int baseDamage = actor.SimulateAttackAmount(situation);
actor.DepriveSneakWithGiveSneakTag();
int damage = attackTarget.AddDamage(situation, baseDamage, isSkillDamage: false);
if (attackTarget.IsDead)
{
attackTarget.RemoveCard(situation, AIRemovalType.Destroy, isFromSkill: false);
}
if (field.AllyClass.Life > 0 && field.EnemyClass.Life > 0)
{
actor.DealDamageDrain(damage, bestPlayPtn, situation);
situation.ExecuteAllSkillProcess();
if (actor.Life <= 0)
{
actor.RemoveCard(situation, AIRemovalType.Destroy, isFromSkill: false);
}
if (!actor.IsDead)
{
AIAttackTagSimulator.ApplyOtherAfterAttackOrClashTags(field, situation);
situation.ExecuteAllSkillProcess();
}
}
}
private static void SimulateWhenAttackAndWhenFightSkills(AIVirtualAttackInfo situation, AIVirtualField field)
{
AIVirtualCard actor = situation.Actor;
actor.IsNotAttackYet = false;
if (actor.TagCollectionContainer.HasTagCollection(TagCollectionType.WhenAttack))
{
actor.TagCollectionContainer.AttackTags.RegisterConditionPassedTagProgress(field, actor, situation);
}
AIVirtualCard attackTarget = situation.AttackTarget;
if (attackTarget.IsUnit && attackTarget.TagCollectionContainer.HasTagCollection(TagCollectionType.WhenAttack))
{
AttackTagCollection attackTags = attackTarget.TagCollectionContainer.AttackTags;
if (attackTags.HasClashTag)
{
attackTags.RegisterConditionPassedTagProgress(field, attackTarget, situation);
}
}
}
private static void SimulateWhenAttackSelfAndOtherSkills(AIVirtualAttackInfo situation, AIVirtualField field)
{
field.RegisterOtherCardAttackTags(situation);
}
public static void SimulateSkillsBeforeAttackCalculation(AIVirtualAttackInfo situation, AIVirtualField field)
{
AIVirtualCard actor = situation.Actor;
AIVirtualCard attackTarget = situation.AttackTarget;
if (!actor.IsDead && !attackTarget.IsDead && situation.ActionType == AIOperationType.ATTACK)
{
SimulateWhenAttackAndWhenFightSkills(situation, field);
SimulateWhenAttackSelfAndOtherSkills(situation, field);
if (attackTarget.IsUnit && actor.SelfField.AllyClass.Life > 0 && actor.SelfField.EnemyClass.Life > 0)
{
_ = attackTarget.IsDead;
}
}
}
private static void ExecAfterClashSkills(AIVirtualAttackInfo situation, AIVirtualField field, int attackDamage, int defendDamage)
{
AIVirtualCard actor = situation.Actor;
AIVirtualCard attackTarget = situation.AttackTarget;
List<int> bestPlayPtn = field.BestPlayPtn;
actor.AfterClash(attackTarget, attackDamage, isAttacker: true, bestPlayPtn, situation);
attackTarget.AfterClash(actor, defendDamage, isAttacker: false, bestPlayPtn, situation);
AIAttackTagSimulator.ApplyOtherAfterAttackOrClashTags(field, situation);
}
}