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

470 lines
19 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Wizard;
public static class AIVirtualTargetSelectSimulator
{
public static IEnumerator ExecuteTargetSelect(AIVirtualTargetSelectSimulationInfo simulationInfo, AIVirtualField field, AISinglePlayptnRecord playPtnRecord)
{
SimulationResult result = new SimulationResult();
yield return EnemyAICoroutine.GetInstance().StartCoroutine(SimulateTargetSelect(simulationInfo, field, playPtnRecord, result, isBattleSim: false));
AIVirtualCard originalActor = simulationInfo.OriginalActor;
AIOperationType operationType = simulationInfo.OperationType;
field.AI.OprTargetSelect(originalActor, result.SelectedTargets, operationType);
}
public static IEnumerator SimulateTargetSelect(AIVirtualTargetSelectSimulationInfo simulationInfo, AIVirtualField field, AISinglePlayptnRecord playPtnRecord, SimulationResult result, bool isBattleSim)
{
List<AIVirtualTargetSelectInfo> selectInfoList = simulationInfo.SelectInfoList;
if (selectInfoList == null || selectInfoList.Count <= 0)
{
simulationInfo.ForceStopNextPlay();
AIConsoleUtility.LogError("SimulateTargetSelect error!! no candidates!!!!!");
yield break;
}
AIVirtualTargetSelectAction action = simulationInfo.CreateSituationForTargetSelectSimulation();
AISelectedTargetInfoSet preDecidedTargets = field.AI.PreDecidedTargets;
List<AISelectedTargetInfoSet> allTargetPattern = GetAllTargetSelectSimulationPattern(selectInfoList, preDecidedTargets, action, field, playPtnRecord);
if (allTargetPattern == null || allTargetPattern.Count <= 0)
{
simulationInfo.ForceStopNextPlay();
yield break;
}
bool isSecondTargetForbbidenSelectedTarget = selectInfoList.Count > 1 && selectInfoList[1].IsForbiddenSelectedTarget;
for (int i = 0; i < allTargetPattern.Count; i++)
{
AISelectedTargetInfoSet currentPattern = allTargetPattern[i];
AISelectedTargetInfoSet previousBestPattern;
if (simulationInfo.IsFirstAction)
{
simulationInfo.FirstActionTargetTemp = currentPattern;
previousBestPattern = result.SelectedTargets;
}
else
{
previousBestPattern = simulationInfo.CurrentSimulationBestTargetTemp;
}
if (!IsAbleToReplaceDummyTarget(currentPattern, previousBestPattern, isSecondTargetForbbidenSelectedTarget))
{
continue;
}
if (!currentPattern.IsTargetExist(0) && currentPattern.IsTargetExist(1))
{
AIConsoleUtility.LogError("currentPattern.firstTarget is null & secondTaget is not null");
continue;
}
AIVirtualField aIVirtualField = new AIVirtualField(field)
{
BestPlayPtn = new List<int>(playPtnRecord.PlayPtn)
};
AIVirtualCard aIVirtualCard = aIVirtualField.SearchVirtualCard(action.OriginalCard);
AIVirtualCard actor = action.Actor;
AIVirtualTargetSelectAction action2 = new AIVirtualTargetSelectAction(actor.IsSameCard(aIVirtualCard) ? aIVirtualCard : new AIVirtualCard(actor, aIVirtualField), selectedTargetList: currentPattern.GetSimilarTargetInfoSet(aIVirtualField), original: aIVirtualCard, operationType: action.ActionType);
yield return SimulateSinglePattern(action2, simulationInfo, aIVirtualField, result, playPtnRecord, isBattleSim);
if (result.IsRecentlyUpdated)
{
result.SelectedTargets = simulationInfo.FirstActionTargetTemp;
simulationInfo.CurrentSimulationBestTargetTemp = currentPattern;
if (result.IsLethalPlan)
{
break;
}
}
else if (simulationInfo.IsRecentlyUpdatedCurrentSimulationBestTargetTempValue)
{
simulationInfo.CurrentSimulationBestTargetTemp = currentPattern;
}
}
}
private static IEnumerator SimulateSinglePattern(AIVirtualTargetSelectAction action, AIVirtualTargetSelectSimulationInfo simulationInfo, AIVirtualField field, SimulationResult result, AISinglePlayptnRecord playPtnRecord, bool isBattleSim)
{
AIVirtualTargetSelectAction aIVirtualTargetSelectAction = null;
switch (action.ActionType)
{
case AIOperationType.EVOLVE:
if (!isBattleSim)
{
AIVirtualEvolutionSimulator.ManualEvolve(action, field);
}
else
{
aIVirtualTargetSelectAction = action;
}
break;
case AIOperationType.PLAY:
{
PlaySimulationInfo playInfo = AIPlayCardSimulationUtility.CreatePlaySimulationInfo(action.OriginalCard, action, field);
AIVirtualPlaySimulator.PlayCard(action, field, playInfo);
break;
}
default:
throw new NotImplementedException();
}
float removalBonus = GetRemovalBonus(action.SelectedTargets) + simulationInfo.PrevRemovalBonus;
if (!isBattleSim && field.EnemyClass.Life <= 0)
{
result.MaxFieldValue = EnemyAI_Skill.PLAYOUT_VALUE;
result.IsLethalPlan = true;
result.MaxFieldValueAtSelfTurnEnd = result.MaxFieldValue;
result.MaxFieldValueFirstSkill = result.MaxFieldValue;
result.IsRecentlyUpdated = true;
result.FirstActionInfo = new AIVirtualTargetSelectAction(action.Actor, action.OriginalCard, action.ActionType, action.SelectedTargets);
result.BestResultField = field;
yield break;
}
EnemyAI ai = field.AI;
result.IsRecentlyUpdated = false;
SimulationAdditionalActionInfoSet additionalActionInfoSet = new SimulationAdditionalActionInfoSet
{
ForceEvoAction = aIVirtualTargetSelectAction,
ExtraActionBaseList = null,
PlayPtnRecord = playPtnRecord
};
AIBattleSimulationLauncher battleSimLauncher = new AIBattleSimulationLauncher(field, ai, aIVirtualTargetSelectAction == null, null, additionalActionInfoSet);
yield return battleSimLauncher.ExecuteBattleSimulationAI(null, checkTimeOverLogic: true);
IBattleSimulationAI battleSimulationAI = battleSimLauncher.BattleSimAI;
float valueWithBonusPoint = battleSimulationAI.Cr_MaxFieldValue + removalBonus;
AIVirtualTargetSelectSimulationInfo nextPlayCardSimulationInfo = (field.AI.IsRunWeakLogic ? null : simulationInfo.CreateNextPlayCardTargetSelectSimulationInfo(field, removalBonus));
if (nextPlayCardSimulationInfo != null)
{
nextPlayCardSimulationInfo.FieldValueAfterFirstSelectCardPlay = valueWithBonusPoint;
AISinglePlayptnRecord aISinglePlayptnRecord = ai.PlayPtnRecorder.CreateRecordForNextPlayTargetSelectSimulation(action, playPtnRecord, field);
if (aISinglePlayptnRecord == null)
{
simulationInfo.IsCurrentSimulationBestTargetTempNeedsToUpdated(valueWithBonusPoint);
yield break;
}
yield return SimulateTargetSelect(nextPlayCardSimulationInfo, field, aISinglePlayptnRecord, result, isBattleSim: false);
if (nextPlayCardSimulationInfo.IsInterruptedNextPlay)
{
UpdateSimulationResultAfterBattle(result, battleSimulationAI, valueWithBonusPoint, simulationInfo);
}
else
{
simulationInfo.IsCurrentSimulationBestTargetTempNeedsToUpdated(valueWithBonusPoint);
}
}
else
{
UpdateSimulationResultAfterBattle(result, battleSimulationAI, valueWithBonusPoint, simulationInfo);
}
}
private static void UpdateSimulationResultAfterBattle(SimulationResult result, IBattleSimulationAI battleSimulationAI, float valueWithBonus, AIVirtualTargetSelectSimulationInfo simulationInfo)
{
if (IsBetterThanCurrentBestResult(valueWithBonus, simulationInfo.FieldValueAfterFirstSelectCardPlay, battleSimulationAI, result))
{
result.IsLethalPlan = battleSimulationAI.Cr_MaxField.EnemyClass.IsDead;
result.MaxFieldValue = valueWithBonus;
result.MaxFieldValueAtSelfTurnEnd = battleSimulationAI.Cr_MaxFieldValueAtSelfTurnEnd;
result.MaxFieldValueFirstSkill = simulationInfo.FieldValueAfterFirstSelectCardPlay;
result.FirstActionInfo = battleSimulationAI.Cr_FirstActionInfo;
result.BestResultField = battleSimulationAI.Cr_MaxField;
result.IsRecentlyUpdated = true;
}
simulationInfo.IsCurrentSimulationBestTargetTempNeedsToUpdated(valueWithBonus);
}
private static bool IsBetterThanCurrentBestResult(float finalValue, float valueAfterFirstCardPlay, IBattleSimulationAI simulator, SimulationResult bestRecord)
{
if (EnemyAI.IsLargerThan(finalValue, bestRecord.MaxFieldValue))
{
return true;
}
if (EnemyAI.IsSameValue(finalValue, bestRecord.MaxFieldValue) && (EnemyAI.IsLargerThan(valueAfterFirstCardPlay, bestRecord.MaxFieldValueFirstSkill) || EnemyAI.IsLargerThan(simulator.Cr_MaxFieldValueAtSelfTurnEnd, bestRecord.MaxFieldValueAtSelfTurnEnd)))
{
return true;
}
return false;
}
public static List<AISelectedTargetInfoSet> GetAllTargetSelectSimulationPattern(List<AIVirtualTargetSelectInfo> selectInfoList, AISelectedTargetInfoSet preDecidedTargetSet, AIVirtualTargetSelectAction situation, AIVirtualField field, AISinglePlayptnRecord playPtnRecord)
{
if (selectInfoList.Count > 2)
{
throw new Exception("GetAllTargetSelectSimulationPattern error!! selectInfoList.Count == " + selectInfoList.Count);
}
if (selectInfoList.Count == 1)
{
return GetAllSingleTargetSelectSimulationPattern(selectInfoList[0], preDecidedTargetSet, situation, field, playPtnRecord);
}
return GetAllMultipleTargetSelectSimulationpattern(selectInfoList[0], selectInfoList[1], preDecidedTargetSet, situation, field, playPtnRecord);
}
private static List<AISelectedTargetInfoSet> GetAllSingleTargetSelectSimulationPattern(AIVirtualTargetSelectInfo selectInfo, AISelectedTargetInfoSet preDecidedTargetSet, AIVirtualTargetSelectAction situation, AIVirtualField field, AISinglePlayptnRecord playPtnRecord)
{
List<AISelectedTargetInfoSet> list = new List<AISelectedTargetInfoSet>();
if (preDecidedTargetSet != null && preDecidedTargetSet.IsAnyTargetExists() && CheckWhenBurialRiteIsDefault(preDecidedTargetSet, selectInfo))
{
list.Add(preDecidedTargetSet);
}
else
{
List<AISelectedTargetInfo> allTargetPatternList = GetAllTargetPatternList(selectInfo, situation, field, playPtnRecord);
if (allTargetPatternList == null || allTargetPatternList.Count <= 0)
{
return null;
}
bool isReplacedFirstInfoByBurialOrChoice = selectInfo.Type == TargetSelectType.BurialRite || selectInfo.Type == TargetSelectType.Choice;
for (int i = 0; i < allTargetPatternList.Count; i++)
{
AISelectedTargetInfoSet item = CreateTargetInfoSet(allTargetPatternList[i], null, isReplacedFirstInfoByBurialOrChoice);
list.Add(item);
}
}
return list;
}
private static bool CheckWhenBurialRiteIsDefault(AISelectedTargetInfoSet targetInfo, AIVirtualTargetSelectInfo selectInfo)
{
if (targetInfo.PreprocessTarget != null && targetInfo.PreprocessTarget.Type == TargetSelectType.BurialRite && selectInfo.Type == TargetSelectType.Default)
{
return false;
}
return true;
}
private static List<AISelectedTargetInfoSet> GetAllMultipleTargetSelectSimulationpattern(AIVirtualTargetSelectInfo firstSelectInfo, AIVirtualTargetSelectInfo secondSelectInfo, AISelectedTargetInfoSet preDecidedTargetSet, AIVirtualTargetSelectAction situation, AIVirtualField field, AISinglePlayptnRecord playPtnRecord)
{
List<AISelectedTargetInfo> list = null;
List<AISelectedTargetInfo> list2 = null;
bool flag = false;
if (preDecidedTargetSet != null)
{
if (firstSelectInfo.Type == TargetSelectType.BurialRite && preDecidedTargetSet.PreprocessTarget != null && preDecidedTargetSet.PreprocessTarget.HasTarget)
{
list = AIParamQuery.AddElementToList(preDecidedTargetSet.PreprocessTarget, list);
flag = true;
}
if (preDecidedTargetSet.HasChoiceTarget)
{
list = AIParamQuery.AddElementToList(preDecidedTargetSet.ChoiceTarget, list);
flag = true;
}
if (preDecidedTargetSet.IsTargetExist(0))
{
AISelectedTargetInfo element = preDecidedTargetSet.Get(0);
if (flag)
{
list2 = AIParamQuery.AddElementToList(element, list2);
}
else
{
list = AIParamQuery.AddElementToList(element, list);
if (preDecidedTargetSet.IsTargetExist(1))
{
list2 = AIParamQuery.AddElementToList(preDecidedTargetSet.Get(1), list2);
}
}
}
}
if (list == null)
{
list = GetAllTargetPatternList(firstSelectInfo, situation, field, playPtnRecord);
}
if (list2 == null)
{
list2 = GetAllTargetPatternList(secondSelectInfo, situation, field, playPtnRecord);
}
if (list == null || list.Count <= 0 || list2 == null || list2.Count <= 0)
{
return null;
}
List<AISelectedTargetInfoSet> list3 = new List<AISelectedTargetInfoSet>();
AISelectedTargetInfo aISelectedTargetInfo = list2[0];
List<AISelectedTargetInfo> list4 = new List<AISelectedTargetInfo>();
for (int i = 0; i < list.Count; i++)
{
AISelectedTargetInfo aISelectedTargetInfo2 = list[i];
if (secondSelectInfo.IsForbiddenSelectedTarget && aISelectedTargetInfo2.IsSelectedSameTarget(aISelectedTargetInfo))
{
list4.Add(aISelectedTargetInfo2);
continue;
}
AISelectedTargetInfoSet item = CreateTargetInfoSet(aISelectedTargetInfo2, aISelectedTargetInfo, flag);
list3.Add(item);
}
for (int j = 1; j < list2.Count; j++)
{
AISelectedTargetInfo aISelectedTargetInfo3 = list2[j];
AISelectedTargetInfoSet item2 = CreateTargetInfoSet(null, aISelectedTargetInfo3, flag);
list3.Add(item2);
if (list4.Count <= 0)
{
continue;
}
for (int k = 0; k < list4.Count; k++)
{
AISelectedTargetInfo aISelectedTargetInfo4 = list4[k];
if (!secondSelectInfo.IsForbiddenSelectedTarget || !aISelectedTargetInfo4.IsSelectedSameTarget(aISelectedTargetInfo3))
{
AISelectedTargetInfoSet item3 = CreateTargetInfoSet(aISelectedTargetInfo4, aISelectedTargetInfo3, flag);
list3.Add(item3);
}
}
}
return list3;
}
private static List<AISelectedTargetInfo> ConvertTargetPatternArrayToInfoList(List<AIVirtualCard[]> targetPatternArray, TargetSelectType targetSelectType, AIRemovalType removalType)
{
List<AISelectedTargetInfo> list = new List<AISelectedTargetInfo>();
for (int i = 0; i < targetPatternArray.Count; i++)
{
AISelectedTargetInfo aISelectedTargetInfo = new AISelectedTargetInfo(targetSelectType, removalType);
AIVirtualCard[] array = targetPatternArray[i];
foreach (AIVirtualCard target in array)
{
aISelectedTargetInfo.AddTarget(target);
}
list.Add(aISelectedTargetInfo);
}
return list;
}
private static List<AISelectedTargetInfo> GetAllTargetPatternList(AIVirtualTargetSelectInfo selectInfo, AIVirtualTargetSelectAction situation, AIVirtualField field, AISinglePlayptnRecord playPtnRecord)
{
AIVirtualCard actor = situation.Actor;
List<int> playPtn = ((playPtnRecord == null) ? EnemyAI.EmptyPlayPtn : playPtnRecord.PlayPtn);
List<AISelectedTargetInfo> list = new List<AISelectedTargetInfo>();
switch (selectInfo.Type)
{
case TargetSelectType.Choice:
{
AISelectedTargetInfo choiceTargets = selectInfo.GetChoiceTargets(actor, field, playPtn, situation);
if (choiceTargets != null)
{
list.Add(choiceTargets);
}
break;
}
case TargetSelectType.BurialRite:
{
bool isBreakPlayptn;
AISelectedTargetInfo burialSelectTargets = selectInfo.GetBurialSelectTargets(situation, field, selectInfo, playPtnRecord, out isBreakPlayptn);
if (burialSelectTargets != null)
{
list.Add(burialSelectTargets);
}
break;
}
case TargetSelectType.NormalRuleBase:
{
AISelectedTargetInfo ruleBaseTargets = selectInfo.GetRuleBaseTargets(situation, field);
if (ruleBaseTargets != null)
{
list.Add(ruleBaseTargets);
}
break;
}
case TargetSelectType.Default:
{
List<AIVirtualCard[]> list2 = AIMathematicsLibrary.EnumerateCombinations(selectInfo.Candidates, selectInfo.Count).ToList();
if (list2 != null && list2.Count > 0)
{
list = ConvertTargetPatternArrayToInfoList(list2, selectInfo.Type, selectInfo.RemovalType);
}
break;
}
}
return list;
}
private static AISelectedTargetInfoSet CreateTargetInfoSet(AISelectedTargetInfo firstTarget, AISelectedTargetInfo secondTarget, bool isReplacedFirstInfoByBurialOrChoice)
{
AISelectedTargetInfoSet aISelectedTargetInfoSet = new AISelectedTargetInfoSet();
if (isReplacedFirstInfoByBurialOrChoice)
{
if (firstTarget != null)
{
if (firstTarget.Type == TargetSelectType.BurialRite)
{
aISelectedTargetInfoSet.SetPreprocessTarget(firstTarget);
}
else if (firstTarget.Type == TargetSelectType.Choice)
{
aISelectedTargetInfoSet.SetChoiceTarget(firstTarget);
}
}
aISelectedTargetInfoSet.Set(secondTarget, 0);
}
else
{
aISelectedTargetInfoSet.Set(firstTarget, 0);
aISelectedTargetInfoSet.Set(secondTarget, 1);
}
return aISelectedTargetInfoSet;
}
public static bool IsAbleToReplaceDummyTarget(AISelectedTargetInfoSet currentPattern, AISelectedTargetInfoSet previousBestPattern, bool isSecondTargetForbbidenSelectedTarget)
{
if (previousBestPattern == null)
{
return true;
}
if (previousBestPattern.PreprocessTarget != null && currentPattern.PreprocessTarget == null)
{
currentPattern.SetPreprocessTarget(previousBestPattern.PreprocessTarget);
return true;
}
if (previousBestPattern.ChoiceTarget != null && currentPattern.ChoiceTarget == null)
{
currentPattern.SetChoiceTarget(previousBestPattern.ChoiceTarget);
return true;
}
if (!currentPattern.IsTargetExist(0))
{
AISelectedTargetInfo aISelectedTargetInfo = previousBestPattern.Get(0);
if (!isSecondTargetForbbidenSelectedTarget || !currentPattern.Get(1).IsSelectedSameTarget(aISelectedTargetInfo))
{
currentPattern.Set(aISelectedTargetInfo, 0);
return true;
}
return false;
}
return true;
}
private static float GetRemovalBonus(AISelectedTargetInfoSet selectedTargetInfoSet)
{
float num = 0f;
for (int i = 0; i < AISelectedTargetInfoSet.LENGTH; i++)
{
AISelectedTargetInfo aISelectedTargetInfo = selectedTargetInfoSet.Get(i);
if (aISelectedTargetInfo != null)
{
AIRemovalType removalType = aISelectedTargetInfo.RemovalType;
List<AIVirtualCard> targets = aISelectedTargetInfo.Targets;
for (int j = 0; j < targets.Count; j++)
{
num += GetTargetRemovalBonus(targets[j], removalType);
}
}
}
return num;
}
private static float GetTargetRemovalBonus(AIVirtualCard target, AIRemovalType removalType)
{
float num = 0f;
List<int> emptyPlayPtn = EnemyAI.EmptyPlayPtn;
switch (removalType)
{
case AIRemovalType.Banish:
num += (float)((!target.IsAlly) ? 1 : (-1)) * (target.EvaluateBreakValue(emptyPlayPtn, useIgnoreBreak: true) - target.GetAllBanishBonus(emptyPlayPtn, useIgnoreInBattle: true) - target.EvaluateLeaveValue(emptyPlayPtn, useIgnoreInBattle: true));
break;
case AIRemovalType.Bounce:
num += (float)(target.IsAlly ? 1 : (-1)) * (target.GetBounceBonus() + target.EvaluateLeaveValue(emptyPlayPtn, useIgnoreInBattle: true));
break;
case AIRemovalType.Metamorphose:
num += (float)((!target.IsAlly) ? 1 : (-1)) * (target.EvaluateBreakValue(emptyPlayPtn, useIgnoreBreak: true) + target.GetAllBanishBonus(emptyPlayPtn, useIgnoreInBattle: true));
break;
}
return num;
}
}