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.
205 lines
6.6 KiB
C#
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;
|
|
}
|
|
}
|