using System; using System.Collections.Generic; using System.Linq; using Continentis.MainGame.Card; using Continentis.MainGame.Character; using Continentis.MainGame.Commands; using Continentis.MainGame.Saving; using Continentis.MainGame.UI; using SLSUtilities.General; using UnityEngine; namespace Continentis.MainGame.Combat { /// /// 战斗进行状态枚举 /// public enum CombatState { InProgress, ConfirmingRound, Victory, Defeat } 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 CombatState combatState; } 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() { combatState = CombatState.InProgress; foreach (CharacterBase character in characterController.characters) character.InitializeCards(); currentRound = 0; eventCollection.onCombatStart.Invoke(); foreach (CharacterBase character in characterController.characters) character.DispatchCombatStart(); // 1.2b — 初始化 CombatLogs 并订阅事件 CombatLogs.Instance.Initialize(this); NextRound(); } public void NextRound() { // 战斗已结束则不再推进 if (combatState != CombatState.InProgress) return; 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.Targeting(intendedCard.targets[0]); card.contentSubmodule.dirtyMark = true; } } } } // ── 进入"回合前确认"阶段:等待玩家点击 Confirm ─────────────────── combatState = CombatState.ConfirmingRound; CommandQueueManager.Instance.AddCommand(Cmd.Do(() => { CombatMainPage page = CombatUIManager.Instance.combatMainPage; page.SetButtonAction(ConfirmRound, "Confirm", true); })); CommandBase waitSignal = Cmd.WaitForSignal(out confirmRoundSignal); CommandQueueManager.Instance.AddCommand(waitSignal); // ── 玩家确认后,回合正式开始:Buff 触发链入队 ──────────────────── CommandQueueManager.Instance.AddCommand(Cmd.Do(() => { combatState = CombatState.InProgress; CombatUIManager.Instance.combatMainPage.SetButtonAction( EndAction, "Waiting...", false); })); foreach (CharacterBase character in characterController.characters) { CharacterBase captured = character; CommandQueueManager.Instance.AddCommand(Cmd.Do(() => captured.DispatchRoundStart())); } // ── 所有回合开始事件处理完毕后,进入第一个行动 ──────────────────── CommandQueueManager.Instance.AddCommand(Cmd.Do(NextAction)); } /// /// 玩家在"回合前确认"阶段点击 Confirm 后调用,释放队列暂停信号。 /// public void ConfirmRound() { if (combatState != CombatState.ConfirmingRound) return; confirmRoundSignal?.Invoke(); confirmRoundSignal = null; } // 持有当前回合的信号委托,ConfirmRound() 调用后置 null 防止重复触发 private Action confirmRoundSignal; public void NextAction() { // 战斗已结束则不再推进 if (combatState != CombatState.InProgress) return; if (characterController.actionOrderList.Count == 0) { // 回合结束:所有角色的 onRoundEnd 和 Buff 触发均入队 foreach (CharacterBase character in characterController.characters) { CharacterBase captured = character; CommandQueueManager.Instance.AddCommand(Cmd.Do(() => captured.DispatchRoundEnd())); } CommandQueueManager.Instance.AddCommand(Cmd.Do(NextRound)); return; } currentCharacter = characterController.actionOrderList[0]; CharacterBase actionCharacter = currentCharacter; CommandQueueManager.Instance.AddCommand(Cmd.Do(() => { actionCharacter.DispatchActionStart(); actionCharacter.recordSubmodule.SetAction(currentRound, ++currentActionIndex); })); CombatMainPage combatMainPage = CombatUIManager.Instance.combatMainPage; if (currentCharacter is PlayerHero playerHero) { 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); combatMainPage.SetButtonAction(EndAction, "End Action", true); } else if (currentCharacter is CombatNPC) { string npcLabel = currentCharacter.fraction switch { Fraction.Enemy => "Enemy Action", Fraction.Ally => "Ally Action", _ => "Others Action" }; combatMainPage.SetButtonAction(null, npcLabel, false); CommandQueueManager.Instance.AddCommand(Cmd.Wait(0.25f)); // 2.3e — PreAction 钩子:NPC 出牌前 CommandQueueManager.Instance.AddCommand(Cmd.Do(() => currentCharacter.intentionSubmodule.currentIntention.PreAction())); 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) )); } // 2.3e — PostAction 钩子:NPC 出完全部卡牌后 CommandQueueManager.Instance.AddCommand(Cmd.Do(() => currentCharacter.intentionSubmodule.currentIntention.PostAction())); 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.SetButtonAction(null, "Waiting...", false); CommandQueueManager.Instance.AddCommand(Cmd.Do(() => { currentCharacter.DispatchActionEnd(); 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)); })); } } public partial class CombatMainManager { /// /// 结束战斗,触发胜负流程。由 CombatCharacterController.CheckCombatEnd() 调用。 /// public void EndCombat(bool isVictory) { // 防止重复触发 if (combatState != CombatState.InProgress) return; combatState = isVictory ? CombatState.Victory : CombatState.Defeat; // 触发战斗结束全局事件 eventCollection.onCombatEnd.Invoke(); foreach (CharacterBase character in characterController.characters) character.DispatchCombatEnd(); // 清理所有卡牌 Logic 的托管订阅 foreach (CharacterBase character in characterController.characters) foreach (CardInstance card in character.deckSubmodule.GetAllCards()) card.cardLogic?.Dispose(); if (isVictory) { CombatVictory(); } else { CombatDefeat(); } } /// /// 战斗胜利处理:收集战后英雄 HP,通知 MainGameManager 推进节点并存档。 /// private void CombatVictory() { CombatUIManager.Instance.combatMainPage.SetButtonAction(null, "Victory!", false); // 将玩家英雄的战后 HP 与 RunSave 中的 HeroSave 对应:按 currentRun.heroes 顺序匹配 var heroResults = new List<(string heroID, int currentHP)>(); List runHeroes = MainGameManager.Instance.currentRun?.heroes; if (runHeroes != null) { for (int i = 0; i < Mathf.Min(characterController.playerHeroes.Count, runHeroes.Count); i++) { int hp = Mathf.RoundToInt(characterController.playerHeroes[i].GetAttribute("Health")); heroResults.Add((runHeroes[i].characterDataID, hp)); } } // CommandQueue 执行完毕后再切场景,避免队列中残余命令在新场景报错 CommandQueueManager.Instance.AddCommand(Cmd.Do(() => MainGameManager.Instance.ExitCombat(isVictory: true, heroResults))); } /// /// 战斗失败处理:通知 MainGameManager 删档并返回主菜单。 /// private void CombatDefeat() { CombatUIManager.Instance.combatMainPage.SetButtonAction(null, "Defeat...", false); CommandQueueManager.Instance.AddCommand(Cmd.Do(() => MainGameManager.Instance.ExitCombat(isVictory: false))); } } }