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.
747 lines
27 KiB
C#
747 lines
27 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
|
|
namespace Wizard;
|
|
|
|
public static class AISimulationUtility
|
|
{
|
|
public static int FULL_SIMULATION_MOVE_COUNT_TURESHOLD = 16;
|
|
|
|
public static float ILLEGAL_PLAYPTN_VALUE = -1000f;
|
|
|
|
private static readonly int[] PATTERN_GROUP_FOR_5 = new int[1] { 31 };
|
|
|
|
private static readonly int[] PATTERN_GROUP_FOR_4 = new int[5] { 30, 29, 27, 23, 15 };
|
|
|
|
private static readonly int[] PATTERN_GROUP_FOR_3 = new int[10] { 28, 26, 25, 22, 21, 19, 14, 13, 11, 7 };
|
|
|
|
private static readonly int[] PATTERN_GROUP_FOR_2 = new int[10] { 24, 20, 18, 17, 12, 10, 9, 6, 5, 3 };
|
|
|
|
private static readonly int[] PATTERN_GROUP_FOR_1 = new int[5] { 16, 8, 4, 2, 1 };
|
|
|
|
private static ulong[] PRIME_NUMBERS_FOR_ENEMY = new ulong[6] { 67uL, 9221uL, 181uL, 271939uL, 3001uL, 12277uL };
|
|
|
|
private static ulong[] PRIME_NUMBERS_FOR_ALLY = new ulong[6] { 4919uL, 11149uL, 187651uL, 139uL, 3011uL, 2003uL };
|
|
|
|
public static List<AIVirtualActionInfo> GetActionInfoSequence(AIVirtualField field, int[] permList, bool[] isAttackFollowerFlags, int evoIndex)
|
|
{
|
|
List<AIVirtualActionInfo> list = new List<AIVirtualActionInfo>();
|
|
if (permList != null && permList.Length <= field.AllyInplayCards.Count((AIVirtualCard c) => c.IsUnit) && permList.Length == isAttackFollowerFlags.Length)
|
|
{
|
|
for (int num = 0; num < permList.Length; num++)
|
|
{
|
|
int num2 = permList[num];
|
|
AIVirtualCard originalActor = field.AllyInplayCards[num2];
|
|
AIVirtualCard currentFieldActor = field.AllyInplayCards.FirstOrDefault((AIVirtualCard card) => card.CardIndex == originalActor.CardIndex);
|
|
if (currentFieldActor == null)
|
|
{
|
|
break;
|
|
}
|
|
if (num2 == evoIndex && !currentFieldActor.IsEvolution)
|
|
{
|
|
field.AllyInplayCards[num2].IsUseEvo = true;
|
|
if (field.CardListSet.AllyClassAndInplayCards.Any((AIVirtualCard c) => c.IsFirstEvo(currentFieldActor, field.BestPlayPtn)))
|
|
{
|
|
list.Insert(0, new AIVirtualTargetSelectAction(currentFieldActor, currentFieldActor, AIOperationType.EVOLVE));
|
|
}
|
|
else
|
|
{
|
|
list.Add(new AIVirtualTargetSelectAction(currentFieldActor, currentFieldActor, AIOperationType.EVOLVE));
|
|
}
|
|
}
|
|
list.Add(new AIVirtualAttackInfo(currentFieldActor, isAttackFollowerFlags[num]));
|
|
}
|
|
}
|
|
field.ActionLength = 0;
|
|
return list;
|
|
}
|
|
|
|
public static List<int> GetEnemyTargets(List<AIVirtualCard> enemyInplayCards, List<int> targetCandidates, int breakPtnIndex, List<int> playPtn)
|
|
{
|
|
List<int> list = new List<int>();
|
|
for (int i = 0; i < targetCandidates.Count; i++)
|
|
{
|
|
int num = targetCandidates[i];
|
|
if (!enemyInplayCards[num].IsAmulet && ((breakPtnIndex >> i) & 1) > 0)
|
|
{
|
|
AddTarget(enemyInplayCards, num, list, playPtn);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
private static void AddTarget(List<AIVirtualCard> targetCandidates, int targetIndex, List<int> virtualCardList, List<int> playPtn)
|
|
{
|
|
AIVirtualCard tagOwner = targetCandidates[targetIndex];
|
|
int num = -1;
|
|
for (int i = 0; i < virtualCardList.Count; i++)
|
|
{
|
|
if (targetCandidates[virtualCardList[i]].IsBreakLast(playPtn))
|
|
{
|
|
num = i;
|
|
break;
|
|
}
|
|
}
|
|
if (tagOwner.IsBreakFirst(playPtn))
|
|
{
|
|
virtualCardList.Insert(0, targetIndex);
|
|
}
|
|
else if (tagOwner.IsBreakLast(playPtn))
|
|
{
|
|
virtualCardList.Add(targetIndex);
|
|
}
|
|
else if (num >= 0)
|
|
{
|
|
virtualCardList.Insert(num, targetIndex);
|
|
}
|
|
else
|
|
{
|
|
virtualCardList.Add(targetIndex);
|
|
}
|
|
}
|
|
|
|
public static List<AIVirtualCard> GetEnemyTargetSequence(AIVirtualField field, List<int> enemyTargetIndexes)
|
|
{
|
|
List<AIVirtualCard> list = new List<AIVirtualCard>();
|
|
for (int i = 0; i < enemyTargetIndexes.Count; i++)
|
|
{
|
|
if (enemyTargetIndexes[i] < field.EnemyInplayCards.Count && enemyTargetIndexes[i] >= 0)
|
|
{
|
|
list.Add(field.EnemyInplayCards[enemyTargetIndexes[i]]);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
public static bool IsValidEnemyTargetIndexes(List<AIVirtualCard> enemyCards, List<int> enemyTargetIndexes)
|
|
{
|
|
if (enemyTargetIndexes.Count > enemyCards.Count)
|
|
{
|
|
return false;
|
|
}
|
|
for (int i = 0; i < enemyTargetIndexes.Count; i++)
|
|
{
|
|
if (enemyCards[enemyTargetIndexes[i]].IsAmulet)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool IsValuableEvoIndex(int evoIndex, AIVirtualField originalField)
|
|
{
|
|
if (evoIndex >= 0 && !originalField.AllyInplayCards[evoIndex].IsUnit)
|
|
{
|
|
return false;
|
|
}
|
|
if (evoIndex >= 0)
|
|
{
|
|
AIVirtualCard aIVirtualCard = originalField.AllyInplayCards[evoIndex];
|
|
AIVirtualTargetSelectAction situation = new AIVirtualTargetSelectAction(aIVirtualCard, aIVirtualCard, AIOperationType.EVOLVE, (AISelectedTargetInfoSet)null);
|
|
if (!aIVirtualCard.IsAbleEvolution() || aIVirtualCard.CreateAIVirtualSelectInfo(originalField, situation) != null)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool IsBestRecord(AIVirtualField field, float currentFieldValue, float valueAtSelfTurnEnd, SimulationResult bestRecord)
|
|
{
|
|
if (field.EnemyClass.IsDead)
|
|
{
|
|
int actionLength = field.ActionLength;
|
|
if (actionLength < bestRecord.MinActionLengthOfLethal || (actionLength == bestRecord.MinActionLengthOfLethal && EnemyAI.IsLargerThan(currentFieldValue, bestRecord.MaxFieldValue)))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (EnemyAI.IsLargerThan(currentFieldValue, bestRecord.MaxFieldValue))
|
|
{
|
|
return true;
|
|
}
|
|
if (EnemyAI.IsSameValue(currentFieldValue, bestRecord.MaxFieldValue) && EnemyAI.IsLargerThan(valueAtSelfTurnEnd, bestRecord.MaxFieldValueAtSelfTurnEnd))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool ExecuteVirtualAction(AIVirtualActionInfo actionInfo, AIVirtualActionInfo evolutionInfo, List<AIVirtualCard> enemyTargetSequence, SimulationSetting setting)
|
|
{
|
|
AIVirtualField selfField = actionInfo.Actor.SelfField;
|
|
if (actionInfo.IsAlreadyUsed)
|
|
{
|
|
_ = (actionInfo.Actor.IsPlayer ? "p" : "e") + actionInfo.Actor.CardIndex;
|
|
return false;
|
|
}
|
|
if (actionInfo.Actor.IsDead)
|
|
{
|
|
actionInfo.IsAlreadyUsed = true;
|
|
return false;
|
|
}
|
|
if (actionInfo.ActionType == AIOperationType.EVOLVE)
|
|
{
|
|
actionInfo.IsAlreadyUsed = true;
|
|
if (actionInfo.Actor.IsEvolution)
|
|
{
|
|
return false;
|
|
}
|
|
if (!actionInfo.Actor.IsUseEvo)
|
|
{
|
|
return false;
|
|
}
|
|
AIVirtualEvolutionSimulator.ManualEvolve(actionInfo, selfField);
|
|
selfField.EvoUsedCard = actionInfo.Actor;
|
|
}
|
|
else if (actionInfo is AIVirtualAttackInfo aIVirtualAttackInfo)
|
|
{
|
|
AIVirtualAttackInfo aIVirtualAttackInfo2 = aIVirtualAttackInfo;
|
|
if (aIVirtualAttackInfo.AttackTarget != null)
|
|
{
|
|
aIVirtualAttackInfo2 = new AIVirtualAttackInfo(aIVirtualAttackInfo.Actor, aIVirtualAttackInfo.IsAttackFollower, aIVirtualAttackInfo.PremiseAction);
|
|
}
|
|
AIVirtualCard aIVirtualCard = BattleSequencer.FindAttackTarget(selfField, aIVirtualAttackInfo2, enemyTargetSequence, evolutionInfo, setting.IsHandRemovalValid, setting.NoSkipAttack, aIVirtualAttackInfo2.IsAttackFollower);
|
|
bool isAttackerUsed = false;
|
|
if (aIVirtualCard != null)
|
|
{
|
|
AIAttackSimulationUtility.SimulateAttackIfValuable(aIVirtualAttackInfo2, selfField, setting.UseLeaderAttackPreCheck, ref isAttackerUsed);
|
|
if (aIVirtualCard.IsDead)
|
|
{
|
|
aIVirtualAttackInfo2.IsBreakTarget = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aIVirtualAttackInfo2.SetAttackTarget(null);
|
|
isAttackerUsed = true;
|
|
}
|
|
actionInfo.IsAlreadyUsed = isAttackerUsed;
|
|
if (!aIVirtualAttackInfo2.IsAttackSuccessed)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static float EvaluateField(AIVirtualField field, EvaluationType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case EvaluationType.FULL:
|
|
return field.EvaluateField() - (field.EnemyClass.IsDead ? 0f : field.EvaluateThreaten());
|
|
case EvaluationType.SELF_TURN:
|
|
case EvaluationType.SIMPLE:
|
|
return field.EvaluateField();
|
|
default:
|
|
return 0f;
|
|
}
|
|
}
|
|
|
|
public static float EvaluateLegalPlayPtnAfterSimulation(AIVirtualField fieldTemp, List<AIVirtualActionInfo> actionInfoSequence, PlayPtnWithToken[] playPtnsWithToken, int openCount, ulong[] defaultPlayptnHashs, out PlayPtnWithToken bestPlayPtnWithToken, out int bestFirstDeadActionIndex)
|
|
{
|
|
bestFirstDeadActionIndex = int.MaxValue;
|
|
bestPlayPtnWithToken = null;
|
|
ulong[] array = CalculatePlayptnWithTokenHashs(fieldTemp, playPtnsWithToken);
|
|
PlayPtnWithToken[] array2 = new PlayPtnWithToken[playPtnsWithToken.Length];
|
|
for (int i = 0; i < playPtnsWithToken.Length; i++)
|
|
{
|
|
PlayPtnWithToken playPtnWithToken = playPtnsWithToken[i];
|
|
if (playPtnWithToken == null || array[i] != defaultPlayptnHashs[i])
|
|
{
|
|
array2[i] = null;
|
|
}
|
|
else
|
|
{
|
|
array2[i] = playPtnWithToken;
|
|
}
|
|
}
|
|
if (array2.Any((PlayPtnWithToken p) => p != null))
|
|
{
|
|
return EvaluatePlayPtnValue(fieldTemp, actionInfoSequence, array2, openCount, out bestPlayPtnWithToken, out bestFirstDeadActionIndex);
|
|
}
|
|
return ILLEGAL_PLAYPTN_VALUE;
|
|
}
|
|
|
|
private static float EvaluatePlayPtnValue(AIVirtualField fieldTemp, List<AIVirtualActionInfo> actionInfoSequence, PlayPtnWithToken[] playPtnsWithToken, int openCount, out PlayPtnWithToken bestPlayPtnWithToken, out int bestFirstDeadActionIndex)
|
|
{
|
|
AIVirtualFieldRollBackBasicProcessor aIVirtualFieldRollBackBasicProcessor = new AIVirtualFieldRollBackBasicProcessor(fieldTemp);
|
|
AIStyleQuery styleQuery = fieldTemp.ParamQuery.styleQuery;
|
|
float num = float.MinValue;
|
|
bestFirstDeadActionIndex = int.MaxValue;
|
|
bestPlayPtnWithToken = null;
|
|
for (int num2 = openCount; num2 >= 0; num2--)
|
|
{
|
|
if (playPtnsWithToken[num2] != null)
|
|
{
|
|
PlayPtnWithToken playPtnWithToken = playPtnsWithToken[num2];
|
|
if (playPtnWithToken != null)
|
|
{
|
|
List<int> list = (fieldTemp.BestPlayPtn = playPtnWithToken.PlayPtn);
|
|
fieldTemp.UpdateBestPlayptnRecordOnSim(list);
|
|
List<TokenPlayPattern> tokenPtn = playPtnWithToken.TokenPtn;
|
|
if (list.Count == tokenPtn.Count)
|
|
{
|
|
float num3 = float.MinValue;
|
|
for (int i = 0; i < fieldTemp.AllyInplayCards.Count; i++)
|
|
{
|
|
AIVirtualCard aIVirtualCard = fieldTemp.AllyInplayCards[i];
|
|
if (aIVirtualCard.IsUnit && !aIVirtualCard.IsDead && aIVirtualCard.IsAbleEvolution())
|
|
{
|
|
float num4 = aIVirtualCard.EvaluateAllEvoBonus(list, new AIVirtualTargetSelectAction(aIVirtualCard, aIVirtualCard, AIOperationType.EVOLVE, (AISelectedTargetInfoSet)null));
|
|
if (num4 > num3)
|
|
{
|
|
num3 = num4;
|
|
}
|
|
}
|
|
}
|
|
float num5 = 0f;
|
|
AISinglePlayptnRecord playptnRecordOnSim = fieldTemp.GetPlayptnRecordOnSim(list);
|
|
for (int j = 0; j < tokenPtn.Count; j++)
|
|
{
|
|
TokenPlayPattern tokenPlayPattern = tokenPtn[j];
|
|
AIVirtualCard aIVirtualCard2 = fieldTemp.AllyHandCards[list[j]];
|
|
AIVirtualTargetSelectAction situation = new AIVirtualTargetSelectAction(aIVirtualCard2, aIVirtualCard2, AIOperationType.PLAY, (AISelectedTargetInfoSet)null);
|
|
AIPreprocessSimulationUtility.SimulatePreprocess(aIVirtualCard2, situation, fieldTemp, AIScriptTokenArgType.WHEN_PLAY, isPseudo: true);
|
|
bool flag = fieldTemp.StyleQuery.IsPlayBreak(aIVirtualCard2, list, situation);
|
|
bool flag2 = playptnRecordOnSim.PlayedCardList[j].PlayType == PlaySimulationType.Accelerate;
|
|
if (!flag && !flag2)
|
|
{
|
|
num5 += aIVirtualCard2.EvaluateValueOnField(list, null, useStyle: true);
|
|
}
|
|
num5 += aIVirtualCard2.EvaluatePlayValue(list, situation);
|
|
num5 += (aIVirtualCard2.GetAllBreakBonus(list, useIgnoreInBattle: false) + aIVirtualCard2.GetAllLeaveBonus(list, useIgnoreInBattle: false)) * (flag ? 1f : EnemyAI.BREAKBONUS_RATE_IN_HAND);
|
|
fieldTemp.UpdateVirtualFieldWhenEvaluation(aIVirtualCard2, situation);
|
|
if (tokenPlayPattern.TokenInfoPairList != null && tokenPlayPattern.TokenInfoPairList.Count > 0)
|
|
{
|
|
for (int k = 0; k < tokenPlayPattern.TokenInfoPairList.Count; k++)
|
|
{
|
|
AITokenInformation aITokenInformation = tokenPlayPattern.TokenInfoPairList[k];
|
|
int tokenId = aITokenInformation.TokenId;
|
|
AIVirtualCard tokenFromId = fieldTemp.AI.tokenManager.GetTokenFromId(tokenId, aIVirtualCard2.IsAlly, fieldTemp);
|
|
num5 += tokenFromId.EvaluateValueOnField(list, null, useStyle: true);
|
|
num5 += (tokenFromId.GetAllBreakBonus(list, useIgnoreInBattle: false) + tokenFromId.GetAllLeaveBonus(list, useIgnoreInBattle: false)) * EnemyAI.BREAKBONUS_RATE_IN_HAND;
|
|
if (aITokenInformation.TokenType == AITokenType.Reanimate)
|
|
{
|
|
num5 += tokenFromId.GetReanimateBonus(list);
|
|
}
|
|
}
|
|
}
|
|
if (j == 0 && aIVirtualCard2.IsFollower(list) && aIVirtualCard2.IsAbleEvolution())
|
|
{
|
|
float num6 = aIVirtualCard2.EvaluateAllEvoBonus(list, new AIVirtualTargetSelectAction(aIVirtualCard2, aIVirtualCard2, AIOperationType.EVOLVE, (AISelectedTargetInfoSet)null));
|
|
if (num6 > num3)
|
|
{
|
|
num5 += num6;
|
|
}
|
|
}
|
|
}
|
|
aIVirtualFieldRollBackBasicProcessor.ResetVirtualFieldToStart();
|
|
num5 += AIEvaluateBonusFromOhterUtility.GetPlayPtnBonus(fieldTemp, list) + styleQuery.GetPlayptnBonus(fieldTemp, list);
|
|
int num7 = int.MaxValue;
|
|
for (int l = 0; l < actionInfoSequence.Count; l++)
|
|
{
|
|
if (actionInfoSequence[l].Actor != null && actionInfoSequence[l].Actor.IsDead)
|
|
{
|
|
num7 = l;
|
|
break;
|
|
}
|
|
}
|
|
if (EnemyAI.IsLargerThan(num5, num) || (EnemyAI.IsSameValue(num5, num) && num7 < bestFirstDeadActionIndex))
|
|
{
|
|
num = num5;
|
|
bestFirstDeadActionIndex = num7;
|
|
bestPlayPtnWithToken = playPtnWithToken;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public static float CalculateMoveFirstBonusValue(List<AIVirtualActionInfo> moves)
|
|
{
|
|
if (moves == null || !moves.Any())
|
|
{
|
|
return 0f;
|
|
}
|
|
AIVirtualCard actor = moves[0].Actor;
|
|
return actor.SelfField.StyleQuery.GetFirstMoveBonus(actor, moves);
|
|
}
|
|
|
|
public static float CalculateOneOnOneBothDeadBonus(List<AIVirtualActionInfo> moves)
|
|
{
|
|
if (moves.Count <= 1 || !(moves[0] is AIVirtualAttackInfo))
|
|
{
|
|
return 0f;
|
|
}
|
|
AIVirtualAttackInfo aIVirtualAttackInfo = moves[0] as AIVirtualAttackInfo;
|
|
if (aIVirtualAttackInfo.Actor.IsDead && aIVirtualAttackInfo.IsBreakTarget)
|
|
{
|
|
return 0.002f;
|
|
}
|
|
return 0f;
|
|
}
|
|
|
|
public static List<AIVirtualActionInfo> GetAllMovesForFullSimulation(AIVirtualField field, bool doesUseEvo, SimulationAdditionalActionInfoSet additionalActionInfoSet)
|
|
{
|
|
AIVirtualTargetSelectAction aIVirtualTargetSelectAction = null;
|
|
List<AIVirtualActionInfo> extraActions = null;
|
|
AISinglePlayptnRecord playPtnRecord = null;
|
|
if (additionalActionInfoSet != null)
|
|
{
|
|
aIVirtualTargetSelectAction = additionalActionInfoSet.ForceEvoAction;
|
|
extraActions = additionalActionInfoSet.ExtraActionBaseList;
|
|
playPtnRecord = additionalActionInfoSet.PlayPtnRecord;
|
|
}
|
|
List<AIVirtualActionInfo> list = null;
|
|
if (doesUseEvo)
|
|
{
|
|
list = GetAllVirtualInplayMove(field);
|
|
}
|
|
else
|
|
{
|
|
list = GetAllVirtualAttackMove(field);
|
|
if (aIVirtualTargetSelectAction != null)
|
|
{
|
|
AIVirtualActionInfo aIVirtualActionInfo = CreateActionInfoOnFieldFromSituation(field, aIVirtualTargetSelectAction);
|
|
if (aIVirtualActionInfo != null)
|
|
{
|
|
list.Add(aIVirtualActionInfo);
|
|
}
|
|
}
|
|
}
|
|
List<AIVirtualActionInfo> allExtraActionList = GetAllExtraActionList(field, extraActions, playPtnRecord);
|
|
if (allExtraActionList != null && allExtraActionList.Count > 0)
|
|
{
|
|
list.AddRange(allExtraActionList);
|
|
}
|
|
list.Add(new AIVirtualTurnEndInfo(field.AllyClass));
|
|
return list;
|
|
}
|
|
|
|
private static List<AIVirtualActionInfo> GetAllVirtualInplayMove(AIVirtualField field)
|
|
{
|
|
List<AIVirtualActionInfo> list = new List<AIVirtualActionInfo>();
|
|
List<AIVirtualActionInfo> allVirtualEvolMove = GetAllVirtualEvolMove(field);
|
|
List<AIVirtualActionInfo> allVirtualAttackMove = GetAllVirtualAttackMove(field);
|
|
for (int i = 0; i < allVirtualEvolMove.Count; i++)
|
|
{
|
|
list.Add(allVirtualEvolMove[i]);
|
|
}
|
|
for (int j = 0; j < allVirtualAttackMove.Count; j++)
|
|
{
|
|
list.Add(allVirtualAttackMove[j]);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
private static List<AIVirtualActionInfo> GetAllVirtualEvolMove(AIVirtualField field)
|
|
{
|
|
List<AIVirtualActionInfo> list = new List<AIVirtualActionInfo>();
|
|
if (field.EvoUsedCard != null)
|
|
{
|
|
return list;
|
|
}
|
|
for (int i = 0; i < field.AllyInplayCards.Count; i++)
|
|
{
|
|
AIVirtualCard aIVirtualCard = field.AllyInplayCards[i];
|
|
if (!aIVirtualCard.IsDead)
|
|
{
|
|
AIVirtualTargetSelectAction aIVirtualTargetSelectAction = new AIVirtualTargetSelectAction(aIVirtualCard, aIVirtualCard, AIOperationType.EVOLVE);
|
|
if (aIVirtualCard.IsAbleEvolution() && aIVirtualCard.CreateAIVirtualSelectInfo(field, aIVirtualTargetSelectAction) == null)
|
|
{
|
|
list.Add(aIVirtualTargetSelectAction);
|
|
}
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
private static List<AIVirtualActionInfo> GetAllVirtualAttackMove(AIVirtualField field)
|
|
{
|
|
List<AIVirtualActionInfo> list = new List<AIVirtualActionInfo>();
|
|
for (int i = 0; i < field.AllyInplayCards.Count; i++)
|
|
{
|
|
AIVirtualCard aIVirtualCard = field.AllyInplayCards[i];
|
|
if (aIVirtualCard.IsDead)
|
|
{
|
|
continue;
|
|
}
|
|
for (int j = 0; j < field.EnemyInplayCards.Count; j++)
|
|
{
|
|
AIVirtualCard aIVirtualCard2 = field.EnemyInplayCards[j];
|
|
AIVirtualAttackInfo aIVirtualAttackInfo = new AIVirtualAttackInfo(aIVirtualCard, aIVirtualCard2);
|
|
if (!aIVirtualCard2.IsDead && AIAttackSimulationUtility.IsAttackPossible(field, aIVirtualAttackInfo))
|
|
{
|
|
list.Add(aIVirtualAttackInfo);
|
|
}
|
|
}
|
|
}
|
|
for (int k = 0; k < field.AllyInplayCards.Count; k++)
|
|
{
|
|
AIVirtualCard aIVirtualCard3 = field.AllyInplayCards[k];
|
|
if (!aIVirtualCard3.IsDead)
|
|
{
|
|
AIVirtualAttackInfo aIVirtualAttackInfo2 = new AIVirtualAttackInfo(aIVirtualCard3, field.EnemyClass);
|
|
if (!field.EnemyClass.IsDead && AIAttackSimulationUtility.IsAttackPossible(field, aIVirtualAttackInfo2))
|
|
{
|
|
list.Add(aIVirtualAttackInfo2);
|
|
}
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
private static List<AIVirtualActionInfo> GetAllExtraActionList(AIVirtualField field, List<AIVirtualActionInfo> extraActions, AISinglePlayptnRecord playPtnRecord)
|
|
{
|
|
if (extraActions == null || extraActions.Count <= 0)
|
|
{
|
|
return null;
|
|
}
|
|
List<AIVirtualActionInfo> list = null;
|
|
for (int i = 0; i < extraActions.Count; i++)
|
|
{
|
|
AIVirtualActionInfo aIVirtualActionInfo = extraActions[i];
|
|
if (aIVirtualActionInfo.ActionType != AIOperationType.PLAY || !(CreateActionInfoOnFieldFromSituation(field, aIVirtualActionInfo) is AIVirtualTargetSelectAction aIVirtualTargetSelectAction))
|
|
{
|
|
continue;
|
|
}
|
|
List<AIVirtualTargetSelectInfo> list2 = aIVirtualTargetSelectAction.Actor.CreateAIVirtualSelectInfo(field, aIVirtualTargetSelectAction);
|
|
if (list2 == null || list2.Count <= 0)
|
|
{
|
|
if (AIPlayCardSimulationUtility.IsAbleToPlayCard(aIVirtualTargetSelectAction, field, EnemyAI.EmptyPlayPtn) && field.AllyInplayCards.Count((AIVirtualCard c) => !c.IsDead) < 5)
|
|
{
|
|
list = AIParamQuery.AddElementToList(aIVirtualTargetSelectAction, list);
|
|
}
|
|
continue;
|
|
}
|
|
AISelectedTargetInfoSet preDecidedTargetSet = null;
|
|
if (aIVirtualTargetSelectAction.SelectedTargets.IsAnyTargetExists())
|
|
{
|
|
preDecidedTargetSet = aIVirtualTargetSelectAction.SelectedTargets;
|
|
}
|
|
List<AISelectedTargetInfoSet> allTargetSelectSimulationPattern = AIVirtualTargetSelectSimulator.GetAllTargetSelectSimulationPattern(list2, preDecidedTargetSet, aIVirtualTargetSelectAction, field, playPtnRecord);
|
|
if (allTargetSelectSimulationPattern == null || allTargetSelectSimulationPattern.Count <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
for (int num = 0; num < allTargetSelectSimulationPattern.Count; num++)
|
|
{
|
|
AISelectedTargetInfoSet selectedTargetList = allTargetSelectSimulationPattern[num];
|
|
AIVirtualTargetSelectAction aIVirtualTargetSelectAction2 = new AIVirtualTargetSelectAction(aIVirtualTargetSelectAction.Actor, aIVirtualTargetSelectAction.OriginalCard, AIOperationType.PLAY, selectedTargetList);
|
|
if (AIPlayCardSimulationUtility.IsAbleToPlayCard(aIVirtualTargetSelectAction2, field, EnemyAI.EmptyPlayPtn) && field.AllyInplayCards.Count < 5)
|
|
{
|
|
list = AIParamQuery.AddElementToList(aIVirtualTargetSelectAction2, list);
|
|
}
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
public static float EvaluateAttackValueAfterAllSkill(AIVirtualField field, AISituationInfo situation, List<AIVirtualCardStatusInfo> allyAttackers, List<AIVirtualCardStatusInfo> enemyRemains, List<int> playPtn)
|
|
{
|
|
for (int i = 0; i < allyAttackers.Count; i++)
|
|
{
|
|
allyAttackers[i].CalculateCardValueWhenDestroyed(playPtn, situation);
|
|
}
|
|
for (int j = 0; j < enemyRemains.Count; j++)
|
|
{
|
|
enemyRemains[j].CalculateCardValueWhenDestroyed(playPtn, situation);
|
|
}
|
|
enemyRemains.OrderBy((AIVirtualCardStatusInfo info) => info.ValueWhenDestroyed);
|
|
float num = 0f;
|
|
AIVirtualAttackInfo aIVirtualAttackInfo = new AIVirtualAttackInfo(null, null);
|
|
for (int num2 = 0; num2 < enemyRemains.Count; num2++)
|
|
{
|
|
AIVirtualCardStatusInfo aIVirtualCardStatusInfo = enemyRemains[num2];
|
|
aIVirtualAttackInfo.SetAttackTarget(aIVirtualCardStatusInfo.BaseCard);
|
|
float num3 = 0f;
|
|
List<AIVirtualCardStatusInfo> usedAttackers = null;
|
|
int num4 = 0;
|
|
List<int> list = null;
|
|
int num5 = (int)Mathf.Pow(2f, allyAttackers.Count);
|
|
for (int num6 = 0; num6 < num5; num6++)
|
|
{
|
|
int num7 = num6;
|
|
int num8 = 0;
|
|
int num9 = 0;
|
|
int num10 = 0;
|
|
float num11 = 0f;
|
|
float num12 = 0f;
|
|
List<AIVirtualCardStatusInfo> list2 = new List<AIVirtualCardStatusInfo>();
|
|
List<int> list3 = new List<int>();
|
|
while (num7 > 0)
|
|
{
|
|
if (num7 % 2 == 1)
|
|
{
|
|
AIVirtualCardStatusInfo aIVirtualCardStatusInfo2 = allyAttackers[num8];
|
|
if (!aIVirtualCardStatusInfo2.BaseCard.IsAttackable(EnemyAI.EmptyPlayPtn))
|
|
{
|
|
num8++;
|
|
num7 /= 2;
|
|
continue;
|
|
}
|
|
aIVirtualAttackInfo.SetActor(aIVirtualCardStatusInfo2.BaseCard);
|
|
list2.Add(aIVirtualCardStatusInfo2);
|
|
num9 += aIVirtualCardStatusInfo.BaseCard.SimulateDamageAmount(aIVirtualCardStatusInfo2.BaseCard.SimulateAttackAmount(aIVirtualCardStatusInfo2.Attack, aIVirtualAttackInfo));
|
|
num10 += aIVirtualCardStatusInfo.BaseCard.SimulateDamageAmount(aIVirtualCardStatusInfo2.BaseCard.SimulateAttackAmount(aIVirtualAttackInfo));
|
|
int num13 = aIVirtualCardStatusInfo2.BaseCard.SimulateDamageAmount(aIVirtualCardStatusInfo.BaseCard.SimulateAttackAmount(aIVirtualCardStatusInfo.Attack, aIVirtualAttackInfo));
|
|
int num14 = aIVirtualCardStatusInfo2.BaseCard.SimulateDamageAmount(aIVirtualCardStatusInfo.BaseCard.SimulateAttackAmount(aIVirtualAttackInfo));
|
|
list3.Add(num13);
|
|
if (num13 >= aIVirtualCardStatusInfo2.Life)
|
|
{
|
|
num11 += aIVirtualCardStatusInfo2.ValueWhenDestroyed;
|
|
}
|
|
int num15 = Mathf.Max(0, aIVirtualCardStatusInfo2.Life - num13);
|
|
int num16 = Mathf.Max(0, aIVirtualCardStatusInfo2.BaseCard.Life - num14);
|
|
num12 += (float)(num15 - num16);
|
|
}
|
|
num8++;
|
|
num7 /= 2;
|
|
}
|
|
float num17 = 0f;
|
|
num17 = ((num10 >= aIVirtualCardStatusInfo.BaseCard.Life) ? 0f : ((num9 >= aIVirtualCardStatusInfo.Life) ? (aIVirtualCardStatusInfo.ValueWhenDestroyed - num11) : 0f));
|
|
num17 += num12;
|
|
if (num3 < num17)
|
|
{
|
|
num3 = num17;
|
|
usedAttackers = list2;
|
|
num4 = num9;
|
|
list = list3;
|
|
}
|
|
}
|
|
if (usedAttackers != null && list != null)
|
|
{
|
|
allyAttackers.RemoveAll((AIVirtualCardStatusInfo card) => usedAttackers.Contains(card));
|
|
num += num3;
|
|
for (int num18 = 0; num18 < usedAttackers.Count; num18++)
|
|
{
|
|
AIVirtualCardStatusInfo aIVirtualCardStatusInfo3 = usedAttackers[num18];
|
|
int num19 = list[num18];
|
|
aIVirtualCardStatusInfo3.ModifyStatus(aIVirtualCardStatusInfo3.Attack, aIVirtualCardStatusInfo3.Life - num19);
|
|
}
|
|
aIVirtualCardStatusInfo.ModifyStatus(aIVirtualCardStatusInfo.Attack, aIVirtualCardStatusInfo.Life - num4);
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public static int[] GetPatternGroup(int count)
|
|
{
|
|
return count switch
|
|
{
|
|
5 => PATTERN_GROUP_FOR_5,
|
|
4 => PATTERN_GROUP_FOR_4,
|
|
3 => PATTERN_GROUP_FOR_3,
|
|
2 => PATTERN_GROUP_FOR_2,
|
|
1 => PATTERN_GROUP_FOR_1,
|
|
_ => null,
|
|
};
|
|
}
|
|
|
|
public static int Factorial(int n)
|
|
{
|
|
if (n <= 1)
|
|
{
|
|
return 1;
|
|
}
|
|
return n * Factorial(n - 1);
|
|
}
|
|
|
|
public static ulong CalculateTargetSequenceHash(int[] permList, AIVirtualField field)
|
|
{
|
|
ulong num = 0uL;
|
|
for (int i = 0; i < permList.Length; i++)
|
|
{
|
|
AIVirtualCard aIVirtualCard = field.EnemyInplayCards[permList[i]];
|
|
num += aIVirtualCard.GetHash() * PRIME_NUMBERS_FOR_ENEMY[i];
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public static ulong CalculateAttackSequenceHash(int[] permList, AIVirtualField field)
|
|
{
|
|
ulong num = 0uL;
|
|
for (int i = 0; i < permList.Length; i++)
|
|
{
|
|
AIVirtualCard aIVirtualCard = field.AllyInplayCards[permList[i]];
|
|
num += aIVirtualCard.GetHash() * PRIME_NUMBERS_FOR_ALLY[i];
|
|
}
|
|
return num;
|
|
}
|
|
|
|
public static ulong[] CalculatePlayptnWithTokenHashs(AIVirtualField field, PlayPtnWithToken[] bestPlayptnWithTokens)
|
|
{
|
|
if (bestPlayptnWithTokens == null)
|
|
{
|
|
return null;
|
|
}
|
|
ulong[] array = new ulong[bestPlayptnWithTokens.Length];
|
|
for (int i = 0; i < bestPlayptnWithTokens.Length; i++)
|
|
{
|
|
PlayPtnWithToken playPtnWithToken = bestPlayptnWithTokens[i];
|
|
if (playPtnWithToken == null)
|
|
{
|
|
array[i] = 0uL;
|
|
}
|
|
else
|
|
{
|
|
array[i] = field.CalculatePlayptnHash(playPtnWithToken.PlayPtn);
|
|
}
|
|
}
|
|
return array;
|
|
}
|
|
|
|
public static AIVirtualActionInfo CreateActionInfoOnFieldFromSituation(AIVirtualField fieldTemp, AISituationInfo situation)
|
|
{
|
|
if (situation == null || situation.Actor == null)
|
|
{
|
|
return null;
|
|
}
|
|
switch (situation.ActionType)
|
|
{
|
|
case AIOperationType.ATTACK:
|
|
{
|
|
AIVirtualAttackInfo attackInfo = situation as AIVirtualAttackInfo;
|
|
if (attackInfo != null)
|
|
{
|
|
AIVirtualCard sourceCard = fieldTemp.AllyInplayCards.Find((AIVirtualCard c) => c.IsSameCard(attackInfo.Actor));
|
|
AIVirtualCard target = fieldTemp.CardListSet.EnemyClassAndInplayCards.Find((AIVirtualCard c) => c.IsSameCard(attackInfo.AttackTarget));
|
|
return new AIVirtualAttackInfo(sourceCard, target);
|
|
}
|
|
return null;
|
|
}
|
|
case AIOperationType.EVOLVE:
|
|
{
|
|
AIVirtualCard aIVirtualCard2 = fieldTemp.AllyInplayCards.Find((AIVirtualCard c) => c.IsSameCard(situation.Actor));
|
|
if (aIVirtualCard2.IsEvolution)
|
|
{
|
|
return null;
|
|
}
|
|
aIVirtualCard2.IsUseEvo = true;
|
|
AISelectedTargetInfoSet similarTargetInfoSet = situation.SelectedTargets.GetSimilarTargetInfoSet(fieldTemp);
|
|
return new AIVirtualTargetSelectAction(aIVirtualCard2, aIVirtualCard2, AIOperationType.EVOLVE, similarTargetInfoSet);
|
|
}
|
|
case AIOperationType.PLAY:
|
|
{
|
|
AIVirtualCard aIVirtualCard = fieldTemp.AllyHandCards.Find((AIVirtualCard c) => c.IsSameCard(situation.OriginalCard));
|
|
if (aIVirtualCard == null)
|
|
{
|
|
return null;
|
|
}
|
|
return new AIVirtualTargetSelectAction(aIVirtualCard.IsSameCard(situation.Actor) ? aIVirtualCard : new AIVirtualCard(situation.Actor, fieldTemp), aIVirtualCard, AIOperationType.PLAY);
|
|
}
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
}
|