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.
This commit is contained in:
391
SVSim.BattleEngine/Engine/Wizard/AIInstantAttackUtility.cs
Normal file
391
SVSim.BattleEngine/Engine/Wizard/AIInstantAttackUtility.cs
Normal file
@@ -0,0 +1,391 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user