using System.Collections.Generic; using System.Linq; using Continentis.MainGame.Card; using Continentis.MainGame.Character; using Continentis.MainGame.Commands; using Continentis.MainGame.Equipment; using Continentis.MainGame.UI; using SLSFramework.General; using SLSFramework.UModAssistance; using TMPro; using UnityEngine; namespace Continentis.MainGame.Combat { public partial class CombatMainManager : Singleton { public CombatCharacterController characterController; } public partial class CombatMainManager { [Header("Combat State")] public int currentRound; public int currentActionIndex; public CharacterBase currentCharacter; } public partial class CombatMainManager { [Header("Events")] public CombatEventCollection eventCollection; } public partial class CombatMainManager { protected override void Awake() { base.Awake(); characterController = new CombatCharacterController(); eventCollection = new CombatEventCollection(); } private void Start() { characterController.Initialize( MainGameManager.Instance.playerHeroDataList, MainGameManager.Instance.enemyDataList); StartCombat(); CombatUIManager.Instance.UpdateAll(); } } public partial class CombatMainManager { public void StartCombat() { foreach (CharacterBase character in characterController.characters) character.InitializeCards(); currentRound = 0; eventCollection.onCombatStart.Invoke(); foreach (CharacterBase character in characterController.characters) { character.eventSubmodule.onCombatStart.Invoke(); foreach (EquipmentBase equipment in character.equipmentSubmodule.currentEquipments) equipment.eventSubmodule.onCombatStart.Invoke(); } foreach (CardInstance card in characterController.characters .SelectMany(character => character.deckSubmodule.GetAllCards())) { card.eventSubmodule.onCombatStart.Invoke(); } NextRound(); } public void NextRound() { currentRound++; // UI 反馈:回合提示动画(同步,纯 UI 无逻辑影响) CombatUIManager.Instance.combatMainPage.roundHint.PlayRoundHint(currentRound); // ── 纯逻辑初始化(无视觉反馈,同步执行)──────────────────────────── eventCollection.onRoundStart.Invoke(); foreach (CharacterBase character in characterController.characters) character.actionCountThisRound = 0; characterController.SetActionOrder(); CombatUIManager.Instance.combatMainPage.actionOrderDisplayer.InitializeTurnOrder(); currentActionIndex = 0; // ── NPC 意图决策(同步,不产生视觉效果)──────────────────────────── foreach (CharacterBase character in characterController.characters) { if (character is CombatNPC npc) { npc.IntentionBrain(); npc.deckSubmodule.PoolPile.ForEach(card => card.weightSubmodule.RefreshCurrentWeight()); npc.intentionSubmodule.getIntendedCards.Invoke(); foreach (IntendedCard intendedCard in npc.intentionSubmodule.intendedCards) { intendedCard.cardInstance.GenerateIntentionCardView(); if (intendedCard.targets.Count > 0) { CardInstance card = intendedCard.cardInstance; card.eventSubmodule.onTargeting(intendedCard.targets[0]); card.contentSubmodule.dirtyMark = true; } } } } // ── 以下所有事件入队,确保 Buff 触发的视觉效果顺序正确 ──────────── foreach (CharacterBase character in characterController.characters) { CharacterBase captured = character; CommandQueueManager.Instance.AddCommand(Cmd.Do( () => captured.eventSubmodule.onRoundStart.Invoke())); CommandQueueManager.Instance.AddCommand(Cmd.Do( () => captured.equipmentSubmodule.currentEquipments.ForEach( equipment => equipment.eventSubmodule.onRoundStart.Invoke()))); CommandQueueManager.Instance.AddCommand(Cmd.Do( () => captured.combatBuffSubmodule.RoundStart())); } // ── 所有回合开始事件处理完毕后,进入第一个行动 ──────────────────── CommandQueueManager.Instance.AddCommand(Cmd.Do(NextAction)); } public void NextAction() { if (characterController.actionOrderList.Count == 0) { // 回合结束:所有角色的 onRoundEnd 和 Buff 触发均入队 foreach (CharacterBase character in characterController.characters) { CharacterBase captured = character; CommandQueueManager.Instance.AddCommand(Cmd.Do( () => captured.eventSubmodule.onRoundEnd.Invoke())); CommandQueueManager.Instance.AddCommand(Cmd.Do( () => captured.equipmentSubmodule.currentEquipments.ForEach( equipment => equipment.eventSubmodule.onRoundEnd.Invoke()))); CommandQueueManager.Instance.AddCommand(Cmd.Do( () => captured.combatBuffSubmodule.RoundEnd())); } CommandQueueManager.Instance.AddCommand(Cmd.Do(NextRound)); return; } currentCharacter = characterController.actionOrderList[0]; CharacterBase actionCharacter = currentCharacter; CommandQueueManager.Instance.AddCommand(Cmd.Do(() => { actionCharacter.eventSubmodule.onActionStart.Invoke(); actionCharacter.combatBuffSubmodule.ActionStart(); actionCharacter.recordSubmodule.SetAction(currentRound, ++currentActionIndex); })); if (currentCharacter is PlayerHero playerHero) { CombatMainPage combatMainPage = CombatUIManager.Instance.combatMainPage; playerHero.deckSubmodule.SetUpHandCardViews(); combatMainPage.handPile.isUpdatingLayout = false; CommandQueueManager.Instance.AddCommand( playerHero.deckSubmodule.DrawCards(playerHero.GetAttribute("DrawCardAmountPerAction"))); CommandQueueManager.Instance.AddCommand(Cmd.Do(() => { combatMainPage.handPile.isUpdatingLayout = true; })); combatMainPage.combatResourcesDisplayer.SetCharacter(playerHero); CombatUIManager.Instance.combatMainPage.endActionButton .GetComponentInChildren().text = "End Action"; CombatUIManager.Instance.combatMainPage.endActionButton.interactable = true; } else if (currentCharacter is CombatNPC) { if (currentCharacter.fraction == Fraction.Enemy) CombatUIManager.Instance.combatMainPage.endActionButton.GetComponentInChildren().text = "Enemy Action"; else if (currentCharacter.fraction == Fraction.Ally) CombatUIManager.Instance.combatMainPage.endActionButton.GetComponentInChildren().text = "Ally Action"; else CombatUIManager.Instance.combatMainPage.endActionButton.GetComponentInChildren().text = "Others Action"; CombatUIManager.Instance.combatMainPage.endActionButton.interactable = false; CommandQueueManager.Instance.AddCommand(Cmd.Wait(0.25f)); foreach (IntendedCard intendedCard in currentCharacter.intentionSubmodule.intendedCards) { IntendedCard captured = intendedCard; currentCharacter.CheckAvailabilityAndSetTargets(captured.cardInstance, out captured.targets); CommandQueueManager.Instance.AddCommand(Cmd.Sequential( Cmd.Do(() => { captured.cardInstance.Play(captured.targets, currentCharacter); captured.cardInstance.DestroyIntentionCardView(); }), Cmd.Wait(0.25f) )); } CommandQueueManager.Instance.AddCommand(Cmd.Do(EndAction)); } currentCharacter.characterView.hudContainer.UpdateAllHUD(); CombatUIManager.Instance.combatMainPage.actionOrderDisplayer.avatars .Find(avatar => avatar.character == currentCharacter)?.Highlight(true); currentCharacter.actionCountThisRound++; } public void EndAction() { CombatUIManager.Instance.combatMainPage.endActionButton .GetComponentInChildren().text = "Waiting..."; CombatUIManager.Instance.combatMainPage.endActionButton.interactable = false; CommandQueueManager.Instance.AddCommand( Cmd.Do(currentCharacter.eventSubmodule.onActionEnd.Invoke)); foreach (CardInstance card in currentCharacter.deckSubmodule.GetAllCards()) { CardInstance captured = card; CommandQueueManager.Instance.AddCommand( Cmd.Do(captured.eventSubmodule.onActionEnd.Invoke)); } CommandQueueManager.Instance.AddCommand(Cmd.Do(() => { currentCharacter.combatBuffSubmodule.ActionEnd(); if (currentCharacter is PlayerHero playerHero) { List handPile = new List(playerHero.deckSubmodule.HandPile); List cardToRetain = handPile.Where(c => c.HasKeyword("Retain")).ToList(); List cardToExhaust = handPile.Where(c => c.HasKeyword("Ethereal")).ToList(); List cardsToDiscard = handPile.Except(cardToRetain).Except(cardToExhaust).ToList(); CommandQueueManager.Instance.AddCommand(playerHero.deckSubmodule.ExhaustCards(cardToExhaust)); CommandQueueManager.Instance.AddCommand(playerHero.deckSubmodule.DiscardCards(cardsToDiscard, false)); } characterController.actionOrderList.Remove(currentCharacter); CombatUIManager.Instance.combatMainPage.actionOrderDisplayer.EndAction(); CommandQueueManager.Instance.AddCommand(Cmd.Do(CombatUIManager.Instance.combatMainPage.ClearAllCardViews)); CommandQueueManager.Instance.AddCommand(Cmd.Wait(0.5f)); CommandQueueManager.Instance.AddCommand(Cmd.Do(NextAction)); })); } } }