using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Cute; namespace Wizard; public class FullSimulationAI : IBattleSimulationAI { private EnemyAI AI; private int bestMoveCount; private bool _isOverComplexity; private int _bestFirstDeadIndex; private int _originalFieldInplayCount; private ulong[] _defaultPlayptnHashArray; private List _simulationAllMoves; public AIVirtualActionInfo Cr_FirstActionInfo { get; private set; } public AIVirtualField Cr_MaxField { get; private set; } public float Cr_MaxFieldValue { get; private set; } public float Cr_MaxFieldValueAtSelfTurnEnd { get; private set; } public List Cr_MaxActionInfoSequence { get; private set; } public PlayPtnWithToken Cr_BestPlayPtnWithToken { get; private set; } public FullSimulationAI(EnemyAI ai, List allMoves) { AI = ai; Cr_FirstActionInfo = null; bestMoveCount = int.MaxValue; Cr_MaxFieldValue = float.MinValue; Cr_MaxFieldValueAtSelfTurnEnd = float.MinValue; Cr_MaxActionInfoSequence = null; Cr_MaxField = null; _isOverComplexity = false; _originalFieldInplayCount = 0; _simulationAllMoves = allMoves; } public IEnumerator _CrSimulate(AIVirtualField originalField, bool doesUseEvo, bool checkTimeOverLogic, PlayPtnWithToken[] bestPlayPtnsWithToken = null, SimulationAdditionalActionInfoSet additionalActions = null) { _ = originalField.ParamQuery; Cr_FirstActionInfo = null; bestMoveCount = int.MaxValue; Cr_MaxFieldValue = float.MinValue; Cr_MaxFieldValueAtSelfTurnEnd = float.MinValue; Cr_MaxActionInfoSequence = null; Cr_MaxField = null; _isOverComplexity = false; AI.IsInVirutalSimulation = true; _originalFieldInplayCount = originalField.AllyInplayCards.Count((AIVirtualCard c) => !c.IsDead); _defaultPlayptnHashArray = AISimulationUtility.CalculatePlayptnWithTokenHashs(originalField, bestPlayPtnsWithToken); AI.IsFullSimulation = true; ParallelJob job = ParallelJob.Dispatch(delegate { try { List recursiveMoveList = null; RunAllMoves(originalField, doesUseEvo, _simulationAllMoves, bestPlayPtnsWithToken, recursiveMoveList, additionalActions); } catch (Exception) { } }); while (!job.isDone) { yield return null; if (checkTimeOverLogic && AI.IsRunWeakLogic) { AI.IsInVirutalSimulation = false; yield break; } } AI.IsFullSimulation = false; if (_isOverComplexity) { BestInPlayMoveAI safety = new BestInPlayMoveAI(AI); yield return EnemyAICoroutine.GetInstance().StartCoroutine(safety._CrSimulate(originalField, doesUseEvo, checkTimeOverLogic: false, bestPlayPtnsWithToken, additionalActions)); Cr_FirstActionInfo = safety.Cr_FirstActionInfo; Cr_MaxField = safety.Cr_MaxField; Cr_MaxFieldValue = safety.Cr_MaxFieldValue; Cr_MaxActionInfoSequence = safety.Cr_MaxActionInfoSequence; } AI.IsInVirutalSimulation = false; } private void RunAllMoves(AIVirtualField field, bool doesUseEvo, List allMoveSet, PlayPtnWithToken[] bestPlayPtnsWithToken, List recursiveMoveList, SimulationAdditionalActionInfoSet additionalActions) { if (AI.IsRunWeakLogic) { return; } if (allMoveSet.Count > AISimulationUtility.FULL_SIMULATION_MOVE_COUNT_TURESHOLD) { _isOverComplexity = true; return; } AIVirtualTargetSelectAction aIVirtualTargetSelectAction = null; if (additionalActions != null) { aIVirtualTargetSelectAction = additionalActions.ForceEvoAction; } if (aIVirtualTargetSelectAction != null && !IsAttackPlanContainsSituation(recursiveMoveList, aIVirtualTargetSelectAction) && !IsAttackPlanContainsSituation(allMoveSet, aIVirtualTargetSelectAction)) { return; } List list = new List(); bool isPlayptnSimulation = bestPlayPtnsWithToken != null; for (int i = 0; i < allMoveSet.Count && !AI.IsRunWeakLogic; i++) { AIVirtualField aIVirtualField = new AIVirtualField(field, isLatestAction: false, isPlayptnSimulation); AIVirtualActionInfo cloneActionInfo = GetCloneActionInfo(aIVirtualField, allMoveSet[i]); if (cloneActionInfo == null) { continue; } ulong hash = cloneActionInfo.GetHash(); if (list.Contains(hash)) { continue; } List list2 = ((recursiveMoveList == null) ? new List() : new List(recursiveMoveList)); list2.Add(cloneActionInfo); if (AI.IsRunWeakLogic) { break; } switch (cloneActionInfo.ActionType) { case AIOperationType.PLAY: RunPlay(cloneActionInfo, aIVirtualField); break; case AIOperationType.EVOLVE: RunEvolution(cloneActionInfo, aIVirtualField); break; case AIOperationType.ATTACK: RunAttack(cloneActionInfo, aIVirtualField); break; case AIOperationType.TURNEND: RunTurnEnd(cloneActionInfo, aIVirtualField, bestPlayPtnsWithToken, list2, aIVirtualTargetSelectAction); continue; } if (AI.IsRunWeakLogic) { break; } if (aIVirtualField.EnemyClass.IsDead || aIVirtualField.AllyClass.IsDead) { UpdateBestRecord(aIVirtualField, list2, null, 0, aIVirtualTargetSelectAction); continue; } SimulationAdditionalActionInfoSet simulationAdditionalActionInfoSet = new SimulationAdditionalActionInfoSet { ForceEvoAction = ((cloneActionInfo.ActionType == AIOperationType.EVOLVE) ? null : aIVirtualTargetSelectAction), ExtraActionBaseList = additionalActions?.ExtraActionBaseList, PlayPtnRecord = additionalActions?.PlayPtnRecord }; List allMovesForFullSimulation = AISimulationUtility.GetAllMovesForFullSimulation(aIVirtualField, doesUseEvo, simulationAdditionalActionInfoSet); RunAllMoves(aIVirtualField, doesUseEvo, allMovesForFullSimulation, bestPlayPtnsWithToken, list2, simulationAdditionalActionInfoSet); if (_isOverComplexity || AI.IsRunWeakLogic) { break; } list.Add(hash); } } private void RunPlay(AIVirtualActionInfo play, AIVirtualField field) { PlaySimulationInfo playInfo = AIPlayCardSimulationUtility.CreatePlaySimulationInfo(play.Actor, play, field); AIVirtualPlaySimulator.PlayCard((AIVirtualTargetSelectAction)play, field, playInfo); } private void RunEvolution(AIVirtualActionInfo evolution, AIVirtualField field) { AIVirtualCard actor = evolution.Actor; if (!actor.IsDead && !actor.IsEvolution) { actor.IsUseEvo = true; AIVirtualEvolutionSimulator.ManualEvolve(evolution, field); field.EvoUsedCard = actor; } } private void RunAttack(AIVirtualActionInfo attackSituation, AIVirtualField field) { AIVirtualAttackInfo aIVirtualAttackInfo = attackSituation as AIVirtualAttackInfo; AIVirtualCard actor = aIVirtualAttackInfo.Actor; AIVirtualAttackSimulator.Attack(aIVirtualAttackInfo, field); if (aIVirtualAttackInfo.AttackTarget.IsDead) { aIVirtualAttackInfo.IsBreakTarget = true; } if (aIVirtualAttackInfo.IsAttackSuccessed && actor.TagCollectionContainer.HasTag(AIPlayTagType.PuppetAttack)) { actor.TagCollectionContainer.PuppetAttackTags.ExecutePuppetAttack(actor, aIVirtualAttackInfo, null); } if (aIVirtualAttackInfo.AttackTarget.IsDead) { aIVirtualAttackInfo.IsBreakTarget = true; } } private void RunTurnEnd(AIVirtualActionInfo move, AIVirtualField field, PlayPtnWithToken[] bestPlayPtnsWithToken, List passToNext, AIVirtualTargetSelectAction forceEvoSituation) { int openCount = 0; if (bestPlayPtnsWithToken == null) { BattleSequencer.OnAfterExecuteAttackCommon(field, (AIVirtualTurnEndInfo)move, ref passToNext, isAttackToLeaderAgain: true); } else { openCount = _originalFieldInplayCount - field.AllyInplayCards.Count((AIVirtualCard c) => !c.IsDead); } UpdateBestRecord(field, passToNext, bestPlayPtnsWithToken, openCount, forceEvoSituation); } private void UpdateBestRecord(AIVirtualField fieldTemp, List moves, PlayPtnWithToken[] bestPlayPtnsWithToken, int openCount, AISituationInfo forceEvoSituation) { if (forceEvoSituation != null && !IsAttackPlanContainsSituation(moves, forceEvoSituation)) { return; } float num = AISimulationUtility.EvaluateField(fieldTemp, EvaluationType.SELF_TURN); float num2 = num; int bestFirstDeadActionIndex = int.MaxValue; PlayPtnWithToken bestPlayPtnWithToken = null; if (bestPlayPtnsWithToken != null) { num2 += AISimulationUtility.CalculateOneOnOneBothDeadBonus(moves); num2 += AISimulationUtility.EvaluateLegalPlayPtnAfterSimulation(fieldTemp, moves, bestPlayPtnsWithToken, openCount, _defaultPlayptnHashArray, out bestPlayPtnWithToken, out bestFirstDeadActionIndex); } else { num2 -= (fieldTemp.EnemyClass.IsDead ? 0f : fieldTemp.EvaluateThreaten()); } num2 -= (float)fieldTemp.ActionLength * 0.001f; num2 += AISimulationUtility.CalculateMoveFirstBonusValue(moves); bool flag = false; if (fieldTemp.EnemyClass.IsDead) { if (Cr_MaxField == null || !Cr_MaxField.EnemyClass.IsDead || fieldTemp.ActionLength < bestMoveCount || (fieldTemp.ActionLength == bestMoveCount && EnemyAI.IsLargerThan(num2, Cr_MaxFieldValue))) { if (moves[0].ActionType == AIOperationType.TURNEND) { AI.IsTurnEndLethal = true; } flag = true; } } else if (EnemyAI.IsLargerThan(num2, Cr_MaxFieldValue)) { flag = true; } else if (EnemyAI.IsSameValue(num2, Cr_MaxFieldValue)) { if (bestPlayPtnsWithToken == null) { if (EnemyAI.IsLargerThan(num, Cr_MaxFieldValueAtSelfTurnEnd)) { flag = true; } } else if (bestFirstDeadActionIndex < _bestFirstDeadIndex) { flag = true; } } if (flag) { Cr_MaxFieldValue = num2; Cr_MaxFieldValueAtSelfTurnEnd = num; Cr_MaxActionInfoSequence = moves; Cr_FirstActionInfo = moves[0]; bestMoveCount = fieldTemp.ActionLength; Cr_MaxField = fieldTemp; if (bestPlayPtnsWithToken != null) { _bestFirstDeadIndex = bestFirstDeadActionIndex; Cr_BestPlayPtnWithToken = bestPlayPtnWithToken; } } } private AIVirtualActionInfo GetCloneActionInfo(AIVirtualField fieldTemp, AIVirtualActionInfo action) { if (action == null || action is AIVirtualTurnEndInfo) { return action; } AIVirtualCard aIVirtualCard = null; aIVirtualCard = ((action.ActionType != AIOperationType.PLAY) ? fieldTemp.AllyInplayCards.Find((AIVirtualCard c) => c.CardIndex == action.OriginalCard.CardIndex) : fieldTemp.AllyHandCards.Find((AIVirtualCard c) => c.CardIndex == action.OriginalCard.CardIndex)); if (aIVirtualCard == null) { AIConsoleUtility.LogError("FullSimulationAI.GetCloneActionInfo() error!! Cannot find originalCard!!!!!"); return null; } if (action is AIVirtualTargetSelectAction aIVirtualTargetSelectAction) { return new AIVirtualTargetSelectAction(aIVirtualCard.IsSameCard(action.Actor) ? aIVirtualCard : new AIVirtualCard(action.Actor, fieldTemp), selectedTargetList: aIVirtualTargetSelectAction.SelectedTargets.GetSimilarTargetInfoSet(fieldTemp), original: aIVirtualCard, operationType: action.ActionType); } if (action is AIVirtualAttackInfo) { AIVirtualAttackInfo aIVirtualAttackInfo = action as AIVirtualAttackInfo; AIVirtualCard originalAttackTarget = aIVirtualAttackInfo.AttackTarget; AIVirtualCard target = fieldTemp.CardListSet.EnemyClassAndInplayCards.Find((AIVirtualCard c) => c.CardIndex == originalAttackTarget.CardIndex); return new AIVirtualAttackInfo(aIVirtualCard, target); } return null; } private bool IsAttackPlanContainsSituation(List moves, AISituationInfo situation) { if (moves == null || moves.Count <= 0) { return false; } for (int i = 0; i < moves.Count; i++) { if (moves[i].IsSameSituation(situation)) { return true; } } return false; } }