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.
302 lines
8.6 KiB
C#
302 lines
8.6 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Cute;
|
|
using UnityEngine;
|
|
|
|
namespace Wizard;
|
|
|
|
public class AITimeOverAttackSimulator : IBattleSimulationAI
|
|
{
|
|
private const int NONE_EVOLVE_INDEX = -1;
|
|
|
|
private AIRuleBaseBattleSimulator _ruleBaseSimulator;
|
|
|
|
private SimulationResult _bestResult;
|
|
|
|
private int _originalFieldInplayCount;
|
|
|
|
private ulong[] _defaultPlayptnHashArray;
|
|
|
|
private SimulationAdditionalActionInfoSet _simAdditionalOptions;
|
|
|
|
public AIVirtualField Cr_MaxField
|
|
{
|
|
get
|
|
{
|
|
if (_bestResult == null)
|
|
{
|
|
return null;
|
|
}
|
|
return _bestResult.BestResultField;
|
|
}
|
|
}
|
|
|
|
public float Cr_MaxFieldValue
|
|
{
|
|
get
|
|
{
|
|
if (_bestResult == null)
|
|
{
|
|
return 0f;
|
|
}
|
|
return _bestResult.MaxFieldValue;
|
|
}
|
|
}
|
|
|
|
public float Cr_MaxFieldValueAtSelfTurnEnd
|
|
{
|
|
get
|
|
{
|
|
if (_bestResult == null)
|
|
{
|
|
return 0f;
|
|
}
|
|
return _bestResult.MaxFieldValueAtSelfTurnEnd;
|
|
}
|
|
}
|
|
|
|
public List<AIVirtualActionInfo> Cr_MaxActionInfoSequence => _bestResult.ActionSequence;
|
|
|
|
public PlayPtnWithToken Cr_BestPlayPtnWithToken { get; private set; }
|
|
|
|
public AIVirtualActionInfo Cr_FirstActionInfo { get; private set; }
|
|
|
|
public IEnumerator _CrSimulate(AIVirtualField originalField, bool doesUseEvo, bool checkTimeOverLogic, PlayPtnWithToken[] bestPlayPtnWithToken = null, SimulationAdditionalActionInfoSet additionalActions = null)
|
|
{
|
|
originalField.AI.IsInVirutalSimulation = true;
|
|
_ruleBaseSimulator = new AIRuleBaseBattleSimulator(originalField.AI, bestPlayPtnWithToken, canChangeToTimeOverLogic: true);
|
|
_bestResult = new SimulationResult();
|
|
_originalFieldInplayCount = originalField.AllyInplayCards.Count((AIVirtualCard c) => !c.IsDead);
|
|
_defaultPlayptnHashArray = AISimulationUtility.CalculatePlayptnWithTokenHashs(originalField, bestPlayPtnWithToken);
|
|
_simAdditionalOptions = additionalActions;
|
|
ParallelJob job = ParallelJob.Dispatch(delegate
|
|
{
|
|
try
|
|
{
|
|
AIVirtualField field = new AIVirtualField(originalField);
|
|
int[] attackerIdxList = SortByOneAttackBreak(field);
|
|
if (additionalActions != null)
|
|
{
|
|
_ = additionalActions.ForceEvoAction;
|
|
}
|
|
SimulateEvoPatternBattle(field, attackerIdxList, doesUseEvo);
|
|
if (bestPlayPtnWithToken != null && Cr_MaxField != null)
|
|
{
|
|
int num = Cr_MaxField.AllyInplayCards.Count((AIVirtualCard c) => !c.IsDead);
|
|
int num2 = Mathf.Min(Mathf.Max(0, _originalFieldInplayCount - num), bestPlayPtnWithToken.Length - 1);
|
|
Cr_BestPlayPtnWithToken = null;
|
|
for (int num3 = num2; num3 >= 0; num3--)
|
|
{
|
|
if (bestPlayPtnWithToken[num3] != null)
|
|
{
|
|
Cr_BestPlayPtnWithToken = bestPlayPtnWithToken[num3];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
});
|
|
while (!job.isDone)
|
|
{
|
|
yield return null;
|
|
}
|
|
if (Cr_MaxField != null)
|
|
{
|
|
Cr_FirstActionInfo = BattleSequencer.GetFirstActionInfo(_bestResult.ActionSequence, Cr_MaxField, Cr_MaxField.BestPlayPtn);
|
|
}
|
|
originalField.AI.IsInVirutalSimulation = false;
|
|
}
|
|
|
|
private int[] SortByOneAttackBreak(AIVirtualField field)
|
|
{
|
|
List<int> sortedAttackerIndexList = GetSortedAttackerIndexList(field);
|
|
int num = ((field.EnemyInplayCards != null) ? field.EnemyInplayCards.Count : 0);
|
|
if (num == 0)
|
|
{
|
|
return sortedAttackerIndexList.ToArray();
|
|
}
|
|
List<int> list = new List<int>();
|
|
List<int> list2 = new List<int>();
|
|
List<int> list3 = new List<int>(sortedAttackerIndexList);
|
|
for (int i = 0; i < sortedAttackerIndexList.Count; i++)
|
|
{
|
|
int num2 = 0;
|
|
bool flag = false;
|
|
int num3 = 0;
|
|
for (int j = 0; j < num; j++)
|
|
{
|
|
AIVirtualCard aIVirtualCard = field.AllyInplayCards[sortedAttackerIndexList[i]];
|
|
AIVirtualCard aIVirtualCard2 = field.EnemyInplayCards[j];
|
|
if (!aIVirtualCard2.IsUnit)
|
|
{
|
|
continue;
|
|
}
|
|
int num4 = aIVirtualCard2.SimulateDamageAmount(aIVirtualCard.Attack);
|
|
if (aIVirtualCard2.Life <= num4)
|
|
{
|
|
num2++;
|
|
if (!flag)
|
|
{
|
|
flag = aIVirtualCard2.IsBreakFirst(field.BestPlayPtn);
|
|
}
|
|
if (aIVirtualCard2.IsBreakLast(field.BestPlayPtn))
|
|
{
|
|
num3++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (num2 > 0 && flag)
|
|
{
|
|
int item = sortedAttackerIndexList[i];
|
|
list.Add(item);
|
|
list3.Remove(item);
|
|
}
|
|
else if (num2 == 0 || (num2 > 0 && num3 == num2))
|
|
{
|
|
int item2 = sortedAttackerIndexList[i];
|
|
list2.Add(item2);
|
|
list3.Remove(item2);
|
|
}
|
|
}
|
|
list.AddRange(list3);
|
|
list.AddRange(list2);
|
|
return list.ToArray();
|
|
}
|
|
|
|
private void SimulateEvoPatternBattle(AIVirtualField field, int[] attackerIdxList, bool useEve)
|
|
{
|
|
List<int> sortedAttackTargetIndexList = GetSortedAttackTargetIndexList(field);
|
|
if (((_simAdditionalOptions != null) ? _simAdditionalOptions.ForceEvoAction : null) != null)
|
|
{
|
|
SimulateTargetsBreakPattern(field, attackerIdxList, -1, sortedAttackTargetIndexList);
|
|
return;
|
|
}
|
|
int num = (useEve ? field.AllyInplayCards.Count : 0);
|
|
for (int i = -1; i < num; i++)
|
|
{
|
|
if (AISimulationUtility.IsValuableEvoIndex(i, field))
|
|
{
|
|
SimulateTargetsBreakPattern(field, attackerIdxList, i, sortedAttackTargetIndexList);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SimulateTargetsBreakPattern(AIVirtualField field, int[] attackrIndecies, int evoIndex, List<int> enemyAllTargets)
|
|
{
|
|
List<ulong> list = new List<ulong>();
|
|
List<int> list2 = new List<int>();
|
|
_ruleBaseSimulator.RunSequence(field, attackrIndecies, evoIndex, new List<int>(), _bestResult, _simAdditionalOptions, null, checkActFailure: false);
|
|
list.Add(AISimulationUtility.CalculateTargetSequenceHash(list2.ToArray(), field));
|
|
int num = enemyAllTargets.Count;
|
|
while (num > 0 && !field.AI.IsBattleEnd)
|
|
{
|
|
int[] patternGroup = AISimulationUtility.GetPatternGroup(num);
|
|
if (patternGroup != null)
|
|
{
|
|
for (int i = 0; i < patternGroup.Length; i++)
|
|
{
|
|
List<int> enemyTargets = AISimulationUtility.GetEnemyTargets(field.EnemyInplayCards, enemyAllTargets, patternGroup[i], field.BestPlayPtn);
|
|
ulong item = AISimulationUtility.CalculateTargetSequenceHash(enemyTargets.ToArray(), field);
|
|
if (!list.Contains(item))
|
|
{
|
|
AIOneMoreLastwordUtility.SortEnemyTargetByBreakBonus(field, enemyTargets);
|
|
if (!AISimulationUtility.IsValidEnemyTargetIndexes(field.EnemyInplayCards, enemyTargets))
|
|
{
|
|
return;
|
|
}
|
|
_ruleBaseSimulator.RunSequence(field, attackrIndecies, evoIndex, enemyTargets, _bestResult, _simAdditionalOptions, null, checkActFailure: false);
|
|
list.Add(item);
|
|
}
|
|
}
|
|
}
|
|
num--;
|
|
}
|
|
}
|
|
|
|
private List<int> GetSortedAttackerIndexList(AIVirtualField field)
|
|
{
|
|
List<int> list = new List<int>();
|
|
List<bool> list2 = new List<bool>();
|
|
List<AIVirtualCard> allyInplayCards = field.AllyInplayCards;
|
|
for (int i = 0; i < allyInplayCards.Count; i++)
|
|
{
|
|
list2.Add(AIAttackSimulationUtility.IsAttackPossible(field, allyInplayCards[i].AttackLeaderSituation));
|
|
}
|
|
for (int j = 0; j < allyInplayCards.Count; j++)
|
|
{
|
|
AIVirtualCard aIVirtualCard = allyInplayCards[j];
|
|
if (!aIVirtualCard.IsUnit)
|
|
{
|
|
continue;
|
|
}
|
|
int num = -1;
|
|
for (int k = 0; k < list.Count; k++)
|
|
{
|
|
int index = list[k];
|
|
AIVirtualCard aIVirtualCard2 = allyInplayCards[index];
|
|
if (aIVirtualCard.Attack < aIVirtualCard2.Attack)
|
|
{
|
|
num = k;
|
|
break;
|
|
}
|
|
if (aIVirtualCard.Attack == aIVirtualCard2.Attack && (!list2[j] || list2[index]) && ((!list2[j] && list2[index]) || aIVirtualCard.Life < aIVirtualCard2.Life))
|
|
{
|
|
num = k;
|
|
break;
|
|
}
|
|
}
|
|
if (num >= 0 && num < list.Count)
|
|
{
|
|
list.Insert(num, j);
|
|
}
|
|
else
|
|
{
|
|
list.Add(j);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
private List<int> GetSortedAttackTargetIndexList(AIVirtualField field)
|
|
{
|
|
List<int> list = new List<int>();
|
|
List<int> list2 = new List<int>();
|
|
List<AIVirtualCard> enemyInplayCards = field.EnemyInplayCards;
|
|
for (int i = 0; i < enemyInplayCards.Count; i++)
|
|
{
|
|
AIVirtualCard aIVirtualCard = enemyInplayCards[i];
|
|
if (!aIVirtualCard.IsUnit)
|
|
{
|
|
continue;
|
|
}
|
|
int num = -1;
|
|
List<int> list3 = (aIVirtualCard.IsGuard ? list2 : list);
|
|
for (int j = 0; j < list3.Count; j++)
|
|
{
|
|
AIVirtualCard aIVirtualCard2 = enemyInplayCards[list3[j]];
|
|
if (aIVirtualCard.Life < aIVirtualCard2.Life || (aIVirtualCard.Life == aIVirtualCard2.Life && aIVirtualCard.Attack > aIVirtualCard2.Attack))
|
|
{
|
|
num = j;
|
|
break;
|
|
}
|
|
}
|
|
if (num >= 0 && num < list3.Count)
|
|
{
|
|
list3.Insert(num, i);
|
|
}
|
|
else
|
|
{
|
|
list3.Add(i);
|
|
}
|
|
}
|
|
list2.AddRange(list);
|
|
return list2;
|
|
}
|
|
}
|