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

205 lines
6.6 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Cute;
namespace Wizard;
public class BestOpenSpaceAttackAI
{
private EnemyAI AI;
public AIVirtualActionInfo Cr_FirstActionInfo;
public PlayPtnWithToken Cr_BestPlayPtnWithToken;
private ulong[] _defaultPlayptnHashArray;
public BestOpenSpaceAttackAI(EnemyAI ai)
{
AI = ai;
}
public IEnumerator _CrSimulate(AIVirtualField originalField, PlayPtnWithToken[] bestPlayPtnsWithToken)
{
AI.IsInVirutalSimulation = true;
float maxFieldValue = float.MinValue;
int bestFirstDeadActionIndex = int.MaxValue;
List<AIVirtualActionInfo> bestActionInfoSequence = null;
AIVirtualField bestField = originalField;
Cr_BestPlayPtnWithToken = null;
Cr_FirstActionInfo = null;
_defaultPlayptnHashArray = AISimulationUtility.CalculatePlayptnWithTokenHashs(originalField, bestPlayPtnsWithToken);
ParallelJob job = ParallelJob.Dispatch(delegate
{
try
{
int count = originalField.AllyInplayCards.Count;
List<int> list = new List<int>();
for (int i = 0; i < originalField.AllyInplayCards.Count; i++)
{
AIVirtualCard aIVirtualCard = originalField.AllyInplayCards[i];
int num = 0;
for (num = 0; num < list.Count && !(aIVirtualCard.Value < originalField.AllyInplayCards[list[num]].Value); num++)
{
}
list.Insert(num, i);
}
int num2 = (1 << originalField.AllyInplayCards.Count) - 1;
List<ulong> list2 = new List<ulong>();
for (int j = 0; j <= num2; j++)
{
if (IsValidBreakIndex(originalField.AllyInplayCards, list, j))
{
if (AI.IsBattleEnd || AI.IsRunWeakLogic)
{
break;
}
int[] allyAttackers = GetAllyAttackers(originalField, list, j);
ulong item = AISimulationUtility.CalculateAttackSequenceHash(allyAttackers, originalField);
if (!list2.Contains(item))
{
List<int> list3 = new List<int>();
for (int k = 0; k < originalField.EnemyInplayCards.Count; k++)
{
if (originalField.EnemyInplayCards[k].IsUnit)
{
list3.Add(k);
}
}
if (AI.IsRunWeakLogic)
{
break;
}
List<int[]> list4 = AIMathematicsLibrary.EnumeratePermutations(list3).ToList();
List<ulong> list5 = new List<ulong>();
for (int l = 0; l < list4.Count; l++)
{
List<int> enemyTargetIndexes = list4[l].ToList();
if (AISimulationUtility.IsValidEnemyTargetIndexes(originalField.EnemyInplayCards, enemyTargetIndexes))
{
ulong item2 = AISimulationUtility.CalculateTargetSequenceHash(list4[l], originalField);
if (!list5.Contains(item2))
{
int num3 = (1 << allyAttackers.Length) - 1;
for (int m = 0; m <= num3; m++)
{
if (AI.IsRunWeakLogic)
{
return;
}
bool[] attackLeaderOrFollowerFlags = GetAttackLeaderOrFollowerFlags(m, allyAttackers.Length);
AIVirtualField aIVirtualField = new AIVirtualField(originalField);
List<AIVirtualActionInfo> actionInfoSequence = AISimulationUtility.GetActionInfoSequence(aIVirtualField, allyAttackers, attackLeaderOrFollowerFlags, -1);
List<AIVirtualCard> enemyTargetSequence = AISimulationUtility.GetEnemyTargetSequence(aIVirtualField, enemyTargetIndexes);
BattleSequencer.ExecSimulation(aIVirtualField, actionInfoSequence, enemyTargetSequence, new SimulationSetting(isHandRemovalValid: true, useLeaderAttackPreCheck: false, noSkipAttack: true));
_ = aIVirtualField.EnemyClass.IsDead;
if (AI.IsRunWeakLogic)
{
return;
}
float num4 = AISimulationUtility.EvaluateField(aIVirtualField, EvaluationType.SIMPLE);
if (AI.IsRunWeakLogic)
{
return;
}
int openCount = count - aIVirtualField.AllyInplayCards.Count((AIVirtualCard c) => !c.IsDead);
PlayPtnWithToken bestPlayPtnWithToken = null;
int bestFirstDeadActionIndex2 = int.MaxValue;
float num5 = AISimulationUtility.EvaluateLegalPlayPtnAfterSimulation(aIVirtualField, actionInfoSequence, bestPlayPtnsWithToken, openCount, _defaultPlayptnHashArray, out bestPlayPtnWithToken, out bestFirstDeadActionIndex2);
float num6 = num4 + num5;
if (AI.IsRunWeakLogic)
{
return;
}
if (EnemyAI.IsLargerThan(num6, maxFieldValue) || (EnemyAI.IsSameValue(num6, maxFieldValue) && bestFirstDeadActionIndex2 < bestFirstDeadActionIndex))
{
maxFieldValue = num6;
bestFirstDeadActionIndex = bestFirstDeadActionIndex2;
Cr_BestPlayPtnWithToken = bestPlayPtnWithToken;
bestActionInfoSequence = actionInfoSequence;
bestField = aIVirtualField;
}
}
list5.Add(item2);
}
}
}
list2.Add(item);
}
}
}
}
catch (Exception)
{
}
});
while (!job.isDone)
{
yield return null;
if (AI.IsRunWeakLogic)
{
AI.IsInVirutalSimulation = false;
yield break;
}
}
if (AI.IsBattleEnd)
{
AI.IsInVirutalSimulation = false;
yield break;
}
if (bestActionInfoSequence.Count > 0)
{
Cr_FirstActionInfo = BattleSequencer.GetFirstActionInfo(bestActionInfoSequence, bestField, Cr_BestPlayPtnWithToken.PlayPtn);
}
AI.IsInVirutalSimulation = false;
}
private bool IsValidBreakIndex(List<AIVirtualCard> allyCards, List<int> sortedInplayIndex, int sortedBreakIndex)
{
for (int i = 0; i < allyCards.Count; i++)
{
if (((sortedBreakIndex >> i) & 1) > 0)
{
AIVirtualCard aIVirtualCard = allyCards[sortedInplayIndex[i]];
if (aIVirtualCard.IsAmulet || aIVirtualCard.AttackableCount <= 0)
{
return false;
}
}
}
return true;
}
private int[] GetAllyAttackers(AIVirtualField field, List<int> sortedInplayIndex, int sortedBreakIndex)
{
List<int> list = new List<int>();
for (int i = 0; i < sortedInplayIndex.Count; i++)
{
if (!field.AllyInplayCards[sortedInplayIndex[i]].IsAmulet && ((sortedBreakIndex >> i) & 1) > 0)
{
list.Add(sortedInplayIndex[i]);
}
}
return list.ToArray();
}
private bool[] GetAttackLeaderOrFollowerFlags(int index, int attackerCount)
{
bool[] array = new bool[attackerCount];
for (int i = 0; i < attackerCount; i++)
{
if (((index >> i) & 1) > 0)
{
array[i] = true;
}
else
{
array[i] = false;
}
}
return array;
}
}