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

392 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
namespace Wizard;
public static class AIInstantAttackUtility
{
public static float EvalInstantAttack(int attack, int life, int count, List<int> playPtn, AIVirtualCard owner, AISituationInfo situation, bool isRush = false)
{
AIVirtualField selfField = owner.SelfField;
if (selfField.IsNoInstantAttack)
{
return 0f;
}
AIFunctionResultContainer funcResultContainer = selfField.AI.FuncResultContainer;
AIScriptTokenFuncType funcType = (isRush ? AIScriptTokenFuncType.EVAL_RUSH : AIScriptTokenFuncType.EVAL_INSTANT_ATTACK);
ulong hash = AIFunctionResultHashCalculator.GetHash(owner, selfField, playPtn, null, GetArgumentHash(attack, life, count));
if (funcResultContainer.GetContainsResultValue(funcType, hash, out var getResult))
{
return getResult;
}
List<AIVirtualCard> list = selfField.CardListSet.EnemyClassAndInplayCards.FindAll((AIVirtualCard c) => c.IsUnit && !c.IsCantUnderAnyAttack());
Dictionary<int, float> savedEvaluations = CacheCardsEvaluation(list, playPtn, situation);
Dictionary<int, float> savedBreakBonus = CacheCardsBreakBonus(list);
Dictionary<int, float> savedLeaveBonus = CachedCardsLeaveBonus(list);
int count2 = list.Count;
List<AIVirtualCard> list2 = new List<AIVirtualCard>();
List<AIVirtualCard> list3 = new List<AIVirtualCard>();
for (int num = 0; num < count2; num++)
{
AIVirtualCard aIVirtualCard = list[num];
if (aIVirtualCard.IsGuard)
{
list2.Add(aIVirtualCard);
}
else
{
list3.Add(aIVirtualCard);
}
}
int count3 = list2.Count;
int count4 = list3.Count;
AIVirtualCard aIVirtualCard2 = CreateDummyAttacker(selfField, owner, attack, life, count, isRush);
float num2 = 0f;
if (count3 > 0)
{
int num3 = (int)Mathf.Pow(2f, count3) - 1;
bool isAllGuardDestroyed = false;
float num4 = EvalInstantAttackToCertainBreakOrLeavePattern(aIVirtualCard2, list2, selfField, num3, playPtn, ref isAllGuardDestroyed, savedEvaluations, savedBreakBonus, savedLeaveBonus);
if (!isAllGuardDestroyed)
{
float num5 = 0f;
for (int num6 = num3 - 1; num6 >= 0; num6--)
{
aIVirtualCard2.AttackableCount = count;
aIVirtualCard2.Life = life;
aIVirtualCard2.Attack = attack;
float num7 = EvalInstantAttackToCertainBreakOrLeavePattern(aIVirtualCard2, list2, selfField, num6, playPtn, ref isAllGuardDestroyed, savedEvaluations, savedBreakBonus, savedLeaveBonus);
if (num7 > num5)
{
num5 = num7;
}
}
if (num5 == 0f)
{
num5 = EvalInstantAttackAgainstFollower(list2, owner, selfField, playPtn, aIVirtualCard2);
}
funcResultContainer.AddRecord(funcType, hash, num5);
RemoveDummyCardFromField(selfField);
return num5;
}
num2 = num4;
count = aIVirtualCard2.AttackableCount;
attack = aIVirtualCard2.Attack;
life = aIVirtualCard2.Life;
}
if (count > 0)
{
int num8 = (int)Mathf.Pow(2f, count4);
float num9 = 0f;
for (int num10 = 0; num10 < num8; num10++)
{
aIVirtualCard2.AttackableCount = count;
aIVirtualCard2.Attack = attack;
aIVirtualCard2.Life = life;
bool isAllGuardDestroyed2 = true;
float num11 = EvalInstantAttackToCertainBreakOrLeavePattern(aIVirtualCard2, list3, selfField, num10, playPtn, ref isAllGuardDestroyed2, savedEvaluations, savedBreakBonus, savedLeaveBonus);
if (isRush)
{
if (num11 > num9)
{
num9 = num11;
}
continue;
}
float num12 = num11 + EvalInstantAttackAgainstLeader(aIVirtualCard2, playPtn);
if (num12 > num9)
{
num9 = num12;
}
}
num2 += num9;
}
funcResultContainer.AddRecord(funcType, hash, num2);
RemoveDummyCardFromField(selfField);
return num2;
}
private static float EvalInstantAttackAgainstFollower(List<AIVirtualCard> targetCards, AIVirtualCard owner, AIVirtualField field, List<int> playPtn, AIVirtualCard attacker)
{
float num = 0f;
int num2 = attacker.AttackableCount;
int attack = attacker.Attack;
int num3 = attacker.Life;
for (int i = 0; i < targetCards.Count; i++)
{
AIVirtualCard aIVirtualCard = targetCards[i];
AIVirtualAttackInfo aIVirtualAttackInfo = new AIVirtualAttackInfo(attacker, aIVirtualCard);
EvalInstantAttackInformation evalInstantAttackInformation = new EvalInstantAttackInformation(aIVirtualAttackInfo);
aIVirtualAttackInfo.PseudoSimulateForEvalInstantAttack(field, playPtn, evalInstantAttackInformation);
if (evalInstantAttackInformation.IsAttackerDestroyWhenAttack)
{
continue;
}
int targetLifeBuff = evalInstantAttackInformation.TargetLifeBuff;
int attackerAttackBuff = evalInstantAttackInformation.AttackerAttackBuff;
int attackerLifeBuff = evalInstantAttackInformation.AttackerLifeBuff;
AIBarrierPseudoSimulationInfo targetBarrierInfo = evalInstantAttackInformation.TargetBarrierInfo;
int damage = aIVirtualCard.SimulateDamageShield(attack + attackerAttackBuff);
damage = targetBarrierInfo.SimulateDamageAmount(damage, isSpellDamage: false, isSkillDamage: false);
float num4 = 0f;
int attackerTotalDamage = evalInstantAttackInformation.AttackerTotalDamage;
while (num2 > 0)
{
num3 += attackerLifeBuff - attackerTotalDamage;
if (num3 <= 0)
{
break;
}
damage -= targetLifeBuff;
num4 += (float)damage;
num2--;
}
if (num4 > num)
{
num = num4;
}
}
attacker.AttackableCount = num2;
attacker.Life = num3;
attacker.Attack = attack;
return num;
}
private static float EvalInstantAttackAgainstLeader(AIVirtualCard dummyAttacker, List<int> playPtn)
{
if (dummyAttacker.Life <= 0 || dummyAttacker.AttackableCount <= 0)
{
return 0f;
}
AIVirtualAttackInfo attackLeaderSituation = dummyAttacker.AttackLeaderSituation;
AIVirtualCard attackTarget = attackLeaderSituation.AttackTarget;
AIVirtualField selfField = dummyAttacker.SelfField;
if (attackLeaderSituation == null)
{
AIConsoleUtility.LogError("EvalInstantAttackAgainstLeader(): Leader attack situation is null!!");
return 0f;
}
int num = attackTarget.Life;
for (int i = 0; i < dummyAttacker.AttackableCount; i++)
{
EvalInstantAttackInformation evalInstantAttackInformation = new EvalInstantAttackInformation(attackLeaderSituation);
attackLeaderSituation.PseudoSimulateForEvalInstantAttack(selfField, playPtn, evalInstantAttackInformation);
int targetLifeBuff = evalInstantAttackInformation.TargetLifeBuff;
int attackerAttackBuff = evalInstantAttackInformation.AttackerAttackBuff;
int attackerLifeBuff = evalInstantAttackInformation.AttackerLifeBuff;
int attackerTotalDamage = evalInstantAttackInformation.AttackerTotalDamage;
AIBarrierPseudoSimulationInfo targetBarrierInfo = evalInstantAttackInformation.TargetBarrierInfo;
int damage = attackTarget.SimulateDamageShield(dummyAttacker.Attack + attackerAttackBuff);
damage = targetBarrierInfo.SimulateDamageAmount(damage, isSpellDamage: false, isSkillDamage: false);
dummyAttacker.Life += attackerLifeBuff - attackerTotalDamage;
if (dummyAttacker.Life <= 0)
{
break;
}
damage -= targetLifeBuff;
num -= damage;
if (num <= 0)
{
break;
}
}
return AILeaderLifeEvaluationUtility.Evaluate(num, attackTarget.Life, attackTarget.IsAlly, dummyAttacker.IsAlly);
}
private static Dictionary<int, float> CacheCardsEvaluation(List<AIVirtualCard> targets, List<int> playPtn, AISituationInfo situation, bool useStyle = true)
{
Dictionary<int, float> dictionary = new Dictionary<int, float>();
for (int i = 0; i < targets.Count; i++)
{
AIVirtualCard aIVirtualCard = targets[i];
float value = aIVirtualCard.EvaluateValueOnField(playPtn, situation, useStyle: true);
try
{
dictionary.Add(aIVirtualCard.CardIndex, value);
}
catch (ArgumentException)
{
}
}
return dictionary;
}
private static Dictionary<int, float> CacheCardsBreakBonus(List<AIVirtualCard> targets)
{
Dictionary<int, float> dictionary = new Dictionary<int, float>();
for (int i = 0; i < targets.Count; i++)
{
AIVirtualCard aIVirtualCard = targets[i];
float value = aIVirtualCard.EvaluateBreakValue(EnemyAI.EmptyPlayPtn, useIgnoreBreak: false);
try
{
dictionary.Add(aIVirtualCard.CardIndex, value);
}
catch (ArgumentException)
{
}
}
return dictionary;
}
private static Dictionary<int, float> CachedCardsLeaveBonus(List<AIVirtualCard> targets)
{
Dictionary<int, float> dictionary = new Dictionary<int, float>();
for (int i = 0; i < targets.Count; i++)
{
AIVirtualCard aIVirtualCard = targets[i];
float value = aIVirtualCard.EvaluateLeaveValue(EnemyAI.EmptyPlayPtn, useIgnoreInBattle: true);
try
{
dictionary.Add(aIVirtualCard.CardIndex, value);
}
catch (ArgumentException)
{
}
}
return dictionary;
}
private static float EvalInstantAttackToCertainBreakOrLeavePattern(AIVirtualCard attacker, List<AIVirtualCard> targetCards, AIVirtualField field, int breakPtnIndex, List<int> playPtn, ref bool isAllGuardDestroyed, Dictionary<int, float> savedEvaluations, Dictionary<int, float> savedBreakBonus, Dictionary<int, float> savedLeaveBonus)
{
float num = 0f;
List<int> list = new List<int>();
List<int> list2 = new List<int>();
int count = targetCards.Count;
for (int i = 0; i < count; i++)
{
int num2 = (int)Mathf.Pow(2f, count - i - 1);
if (breakPtnIndex / num2 <= 0)
{
list.Add(i);
continue;
}
list2.Add(i);
breakPtnIndex -= num2;
}
int count2 = list2.Count;
int num3 = attacker.AttackableCount;
int attack = attacker.Attack;
int num4 = attacker.Life;
for (int j = 0; j < count2; j++)
{
if (num3 <= 0)
{
break;
}
if (num4 <= 0)
{
break;
}
int index = list2[j];
AIVirtualCard aIVirtualCard = targetCards[index];
AIVirtualAttackInfo aIVirtualAttackInfo = new AIVirtualAttackInfo(attacker, aIVirtualCard);
EvalInstantAttackInformation evalInstantAttackInformation = new EvalInstantAttackInformation(aIVirtualAttackInfo);
aIVirtualAttackInfo.PseudoSimulateForEvalInstantAttack(field, playPtn, evalInstantAttackInformation);
if (evalInstantAttackInformation.IsAttackerDestroyWhenAttack)
{
continue;
}
int num5 = aIVirtualCard.Life;
int targetLifeBuff = evalInstantAttackInformation.TargetLifeBuff;
int attackerAttackBuff = evalInstantAttackInformation.AttackerAttackBuff;
int attackerLifeBuff = evalInstantAttackInformation.AttackerLifeBuff;
AIBarrierPseudoSimulationInfo targetBarrierInfo = evalInstantAttackInformation.TargetBarrierInfo;
int damage = aIVirtualCard.SimulateDamageShield(attack + attackerAttackBuff);
damage = targetBarrierInfo.SimulateDamageAmount(damage, isSpellDamage: false, isSkillDamage: false);
int attackerTotalDamage = evalInstantAttackInformation.AttackerTotalDamage;
while (num5 > 0 && num3 > 0)
{
num4 += attackerLifeBuff - attackerTotalDamage;
if (num4 <= 0)
{
break;
}
num5 += targetLifeBuff;
num5 -= damage;
num3--;
if (num5 <= 0)
{
savedEvaluations.TryGetValue(aIVirtualCard.CardIndex, out var value);
savedBreakBonus.TryGetValue(aIVirtualCard.CardIndex, out var value2);
savedLeaveBonus.TryGetValue(aIVirtualCard.CardIndex, out var value3);
num += value - value2 - value3;
isAllGuardDestroyed = j == count2 - 1;
}
}
attacker.AttackableCount = num3;
attacker.Life = num4;
attacker.Attack = attack;
}
return num;
}
public static AIVirtualCard CreateDummyAttacker(AIVirtualField field, AIVirtualCard owner, int attack, int life, int attackableCount, bool isEvalRush)
{
AIVirtualCardParameter baseParameter = new AIVirtualCardParameter(attack, life, attackableCount);
AIVirtualCard aIVirtualCard = new AIVirtualCard(field, baseParameter, owner, isEvalRush);
if (aIVirtualCard.IsAlly)
{
field.AllyInplayCards.Add(aIVirtualCard);
field.CardListSet.AddAllyInplayCard(aIVirtualCard);
}
else
{
field.EnemyInplayCards.Add(aIVirtualCard);
field.CardListSet.AddEnemyInplayCard(aIVirtualCard);
}
return aIVirtualCard;
}
public static void RemoveDummyCardFromField(AIVirtualField field)
{
List<AIVirtualCard> list = null;
for (int i = 0; i < field.AllyInplayCards.Count; i++)
{
AIVirtualCard aIVirtualCard = field.AllyInplayCards[i];
if (IsDummyCard(aIVirtualCard))
{
list = AIParamQuery.AddElementToList(aIVirtualCard, list);
}
}
if (list != null && list.Count > 0)
{
for (int j = 0; j < list.Count; j++)
{
AIVirtualCard aIVirtualCard2 = list[j];
field.AllyInplayCards.Remove(aIVirtualCard2);
field.CardListSet.RemoveAllyInplayCard(aIVirtualCard2);
}
}
List<AIVirtualCard> list2 = null;
for (int k = 0; k < field.EnemyInplayCards.Count; k++)
{
AIVirtualCard aIVirtualCard3 = field.EnemyInplayCards[k];
if (IsDummyCard(aIVirtualCard3))
{
list2 = AIParamQuery.AddElementToList(aIVirtualCard3, list2);
}
}
if (list2 != null && list2.Count > 0)
{
for (int l = 0; l < list2.Count; l++)
{
AIVirtualCard aIVirtualCard4 = list2[l];
field.EnemyInplayCards.Remove(aIVirtualCard4);
field.CardListSet.RemoveEnemyInplayCard(aIVirtualCard4);
}
}
}
private static bool IsDummyCard(AIVirtualCard card)
{
return card.CardParameter.CardName == "Dummy";
}
private static ulong GetArgumentHash(int damage, int life, int count)
{
return (ulong)(0 + (long)damage * 53L + (long)life * 3L + (long)count * 313L);
}
}