更新
This commit is contained in:
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using Continentis.MainGame.Character;
|
||||
using DG.Tweening;
|
||||
using Lean.Pool;
|
||||
using SLSFramework.General;
|
||||
using SLSFramework.UModAssistance;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
@@ -96,6 +97,8 @@ namespace Continentis.MainGame.Combat
|
||||
npcs[fraction].Add(npc);
|
||||
characters.Add(npc);
|
||||
combatCharacterViews.Add(view);
|
||||
|
||||
CombatMainManager.Instance.eventCollection.onCharacterJoin.Invoke(npc);
|
||||
}
|
||||
|
||||
SetViewPositions();
|
||||
@@ -229,6 +232,22 @@ namespace Continentis.MainGame.Combat
|
||||
Object.Destroy(character.characterView.gameObject);
|
||||
|
||||
SetViewPositions();
|
||||
CheckCombatEnd();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查战斗胜负条件:敌方全灭→胜利,玩家方全灭→失败。
|
||||
/// </summary>
|
||||
private void CheckCombatEnd()
|
||||
{
|
||||
if (enemies.Count == 0)
|
||||
{
|
||||
CombatMainManager.Instance.EndCombat(isVictory: true);
|
||||
}
|
||||
else if (playerHeroes.Count == 0)
|
||||
{
|
||||
CombatMainManager.Instance.EndCombat(isVictory: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,10 +285,9 @@ namespace Continentis.MainGame.Combat
|
||||
enemiesList.AddRange(npcs[Fraction.Ally]);
|
||||
return enemiesList;
|
||||
}
|
||||
else // Neutral
|
||||
else // Neutral:中立单位视所有非中立方为敌人
|
||||
{
|
||||
List<CharacterBase> enemiesList = new List<CharacterBase>();
|
||||
enemiesList.AddRange(npcs[Fraction.Player]);
|
||||
List<CharacterBase> enemiesList = new List<CharacterBase>(playerHeroes);
|
||||
enemiesList.AddRange(npcs[Fraction.Ally]);
|
||||
enemiesList.AddRange(npcs[Fraction.Enemy]);
|
||||
return enemiesList;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Continentis.MainGame.Character;
|
||||
using SoftCircuits.Collections;
|
||||
using SLSFramework.General;
|
||||
using UnityEngine;
|
||||
@@ -27,13 +28,25 @@ namespace Continentis.MainGame.Combat
|
||||
/// 回合结束
|
||||
/// </summary>
|
||||
public OrderedDictionary<string, PrioritizedAction> onRoundEnd;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 角色加入战场时(参数为新加入的角色)
|
||||
/// </summary>
|
||||
public OrderedDictionary<string, PrioritizedAction<CharacterBase>> onCharacterJoin;
|
||||
|
||||
/// <summary>
|
||||
/// 角色死亡时(参数为死亡角色)
|
||||
/// </summary>
|
||||
public OrderedDictionary<string, PrioritizedAction<CharacterBase>> onCharacterDeath;
|
||||
|
||||
public CombatEventCollection()
|
||||
{
|
||||
onCombatStart = new OrderedDictionary<string, PrioritizedAction>();
|
||||
onCombatEnd = new OrderedDictionary<string, PrioritizedAction>();
|
||||
onRoundStart = new OrderedDictionary<string, PrioritizedAction>();
|
||||
onRoundEnd = new OrderedDictionary<string, PrioritizedAction>();
|
||||
onCharacterJoin = new OrderedDictionary<string, PrioritizedAction<CharacterBase>>();
|
||||
onCharacterDeath = new OrderedDictionary<string, PrioritizedAction<CharacterBase>>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,210 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Continentis.MainGame.Card;
|
||||
using Continentis.MainGame.Character;
|
||||
using SLSFramework.General;
|
||||
using UnityEngine;
|
||||
|
||||
public class CombatLogs : MonoBehaviour
|
||||
namespace Continentis.MainGame.Combat
|
||||
{
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
void Start()
|
||||
public enum CombatLogType
|
||||
{
|
||||
|
||||
RoundStart,
|
||||
ActionStart,
|
||||
Attack,
|
||||
BuffApply,
|
||||
BuffRemove,
|
||||
CardPlay,
|
||||
Death
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
public class CombatLogEntry
|
||||
{
|
||||
|
||||
public int round;
|
||||
public int actionIndex;
|
||||
public float timestamp;
|
||||
public CombatLogType type;
|
||||
public string message;
|
||||
public Dictionary<string, object> metadata;
|
||||
|
||||
public CombatLogEntry(int round, int actionIndex, CombatLogType type, string message)
|
||||
{
|
||||
this.round = round;
|
||||
this.actionIndex = actionIndex;
|
||||
this.timestamp = Time.time;
|
||||
this.type = type;
|
||||
this.message = message;
|
||||
this.metadata = new Dictionary<string, object>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 战斗日志系统:记录战斗中的关键事件,支持查询与格式化输出。
|
||||
/// 挂载在战斗场景的 CombatMainManager 同级或子对象上。
|
||||
/// </summary>
|
||||
public class CombatLogs : Singleton<CombatLogs>
|
||||
{
|
||||
private const string LogPrefix = "[CombatLog]";
|
||||
|
||||
private readonly List<CombatLogEntry> allEntries = new List<CombatLogEntry>();
|
||||
private CombatMainManager combatManager;
|
||||
|
||||
// ── 初始化与事件订阅 ──────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// 由 CombatMainManager.StartCombat() 调用,订阅全局及各角色事件。
|
||||
/// </summary>
|
||||
public void Initialize(CombatMainManager manager)
|
||||
{
|
||||
allEntries.Clear();
|
||||
combatManager = manager;
|
||||
|
||||
// 订阅全局回合开始事件
|
||||
manager.eventCollection.onRoundStart.InsertByPriority(
|
||||
"CombatLogs_RoundStart",
|
||||
new PrioritizedAction(() => LogRoundStart(manager.currentRound), 0));
|
||||
|
||||
// 订阅角色攻击完成事件
|
||||
foreach (CharacterBase character in manager.characterController.characters)
|
||||
{
|
||||
SubscribeCharacterEvents(character);
|
||||
}
|
||||
|
||||
// 订阅死亡事件
|
||||
manager.eventCollection.onCharacterDeath.InsertByPriority(
|
||||
"CombatLogs_Death",
|
||||
new PrioritizedAction<CharacterBase>(LogDeath, 0));
|
||||
}
|
||||
|
||||
/// <summary>为单个角色订阅攻击完成事件(可供动态加入战场的角色调用)。</summary>
|
||||
public void SubscribeCharacterEvents(CharacterBase character)
|
||||
{
|
||||
CharacterBase captured = character;
|
||||
character.eventSubmodule.onFinishAttack.InsertByPriority(
|
||||
"CombatLogs_FinishAttack",
|
||||
new PrioritizedAction<CharacterBase, AttackResult>(
|
||||
(target, result) => LogAttack(result), 0));
|
||||
}
|
||||
|
||||
// ── 日志写入 API ──────────────────────────────────────────────────
|
||||
|
||||
/// <summary>记录攻击结果。</summary>
|
||||
public void LogAttack(AttackResult result)
|
||||
{
|
||||
string msg = result.isDodged
|
||||
? $"{result.attacker.data.displayName} 攻击 {result.target.data.displayName}(闪避)"
|
||||
: $"{result.attacker.data.displayName} 攻击 {result.target.data.displayName}:" +
|
||||
$"起始伤害={result.startDamage}, 格挡={result.blockedDamage}, " +
|
||||
$"护盾={result.shieldedDamage}, 实际={result.hurtDamage}";
|
||||
|
||||
var entry = new CombatLogEntry(
|
||||
combatManager.currentRound, combatManager.currentActionIndex,
|
||||
CombatLogType.Attack, msg);
|
||||
entry.metadata["attacker"] = result.attacker.data.displayName;
|
||||
entry.metadata["target"] = result.target.data.displayName;
|
||||
entry.metadata["hurtDamage"] = result.hurtDamage;
|
||||
entry.metadata["isDodged"] = result.isDodged;
|
||||
|
||||
WriteEntry(entry);
|
||||
}
|
||||
|
||||
/// <summary>记录 Buff 施加事件。</summary>
|
||||
public void LogBuffApply(CharacterCombatBuffBase buff, CharacterBase target)
|
||||
{
|
||||
string msg = $"Buff 施加:{buff.GetType().Name} → {target.data.displayName}";
|
||||
var entry = new CombatLogEntry(
|
||||
combatManager.currentRound, combatManager.currentActionIndex,
|
||||
CombatLogType.BuffApply, msg);
|
||||
entry.metadata["buffType"] = buff.GetType().Name;
|
||||
entry.metadata["target"] = target.data.displayName;
|
||||
|
||||
WriteEntry(entry);
|
||||
}
|
||||
|
||||
/// <summary>记录 Buff 移除事件。</summary>
|
||||
public void LogBuffRemove(CharacterCombatBuffBase buff)
|
||||
{
|
||||
string msg = $"Buff 移除:{buff.GetType().Name} ← {buff.attachedCharacter?.data.displayName}";
|
||||
var entry = new CombatLogEntry(
|
||||
combatManager.currentRound, combatManager.currentActionIndex,
|
||||
CombatLogType.BuffRemove, msg);
|
||||
entry.metadata["buffType"] = buff.GetType().Name;
|
||||
|
||||
WriteEntry(entry);
|
||||
}
|
||||
|
||||
/// <summary>记录卡牌使用事件。</summary>
|
||||
public void LogCardPlay(CardInstance card, List<CharacterBase> targets)
|
||||
{
|
||||
StringBuilder targetNames = new StringBuilder();
|
||||
foreach (CharacterBase t in targets)
|
||||
{
|
||||
if (targetNames.Length > 0) targetNames.Append(", ");
|
||||
targetNames.Append(t.data.displayName);
|
||||
}
|
||||
string msg = $"卡牌使用:{card.cardData.displayName} → [{targetNames}]";
|
||||
var entry = new CombatLogEntry(
|
||||
combatManager.currentRound, combatManager.currentActionIndex,
|
||||
CombatLogType.CardPlay, msg);
|
||||
entry.metadata["cardName"] = card.cardData.displayName;
|
||||
|
||||
WriteEntry(entry);
|
||||
}
|
||||
|
||||
/// <summary>记录角色死亡事件。</summary>
|
||||
public void LogDeath(CharacterBase character)
|
||||
{
|
||||
string msg = $"{character.data.displayName} 死亡(回合 {combatManager.currentRound})";
|
||||
var entry = new CombatLogEntry(
|
||||
combatManager.currentRound, combatManager.currentActionIndex,
|
||||
CombatLogType.Death, msg);
|
||||
entry.metadata["character"] = character.data.displayName;
|
||||
entry.metadata["fraction"] = character.fraction.ToString();
|
||||
|
||||
WriteEntry(entry);
|
||||
}
|
||||
|
||||
/// <summary>记录回合开始事件。</summary>
|
||||
public void LogRoundStart(int round)
|
||||
{
|
||||
string msg = $"── 第 {round} 回合开始 ──";
|
||||
var entry = new CombatLogEntry(round, 0, CombatLogType.RoundStart, msg);
|
||||
WriteEntry(entry);
|
||||
}
|
||||
|
||||
// ── 查询 API ──────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>按类型和数量查询日志条目。</summary>
|
||||
public List<CombatLogEntry> Query(CombatLogType type, int lastN = 10)
|
||||
{
|
||||
var result = new List<CombatLogEntry>();
|
||||
for (int i = allEntries.Count - 1; i >= 0 && result.Count < lastN; i--)
|
||||
{
|
||||
if (allEntries[i].type == type)
|
||||
result.Add(allEntries[i]);
|
||||
}
|
||||
result.Reverse();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>获取所有日志条目。</summary>
|
||||
public IReadOnlyList<CombatLogEntry> GetAllEntries() => allEntries;
|
||||
|
||||
// ── 格式化 ────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>将条目格式化为人类可读字符串。</summary>
|
||||
public string FormatEntry(CombatLogEntry entry)
|
||||
{
|
||||
return $"[R{entry.round:D2}|A{entry.actionIndex:D2}|{entry.timestamp:F2}s] {entry.type}: {entry.message}";
|
||||
}
|
||||
|
||||
// ── 内部写入 ──────────────────────────────────────────────────────
|
||||
|
||||
private void WriteEntry(CombatLogEntry entry)
|
||||
{
|
||||
allEntries.Add(entry);
|
||||
Debug.Log($"{LogPrefix} {FormatEntry(entry)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
using System;
|
||||
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.Saving;
|
||||
using Continentis.MainGame.UI;
|
||||
using SLSFramework.General;
|
||||
using SLSFramework.UModAssistance;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Continentis.MainGame.Combat
|
||||
{
|
||||
/// <summary>
|
||||
/// 战斗进行状态枚举
|
||||
/// </summary>
|
||||
public enum CombatState
|
||||
{
|
||||
InProgress,
|
||||
ConfirmingRound,
|
||||
Victory,
|
||||
Defeat
|
||||
}
|
||||
|
||||
public partial class CombatMainManager : Singleton<CombatMainManager>
|
||||
{
|
||||
public CombatCharacterController characterController;
|
||||
@@ -23,6 +33,7 @@ namespace Continentis.MainGame.Combat
|
||||
public int currentRound;
|
||||
public int currentActionIndex;
|
||||
public CharacterBase currentCharacter;
|
||||
public CombatState combatState;
|
||||
}
|
||||
|
||||
public partial class CombatMainManager
|
||||
@@ -54,6 +65,8 @@ namespace Continentis.MainGame.Combat
|
||||
{
|
||||
public void StartCombat()
|
||||
{
|
||||
combatState = CombatState.InProgress;
|
||||
|
||||
foreach (CharacterBase character in characterController.characters)
|
||||
character.InitializeCards();
|
||||
|
||||
@@ -62,23 +75,19 @@ namespace Continentis.MainGame.Combat
|
||||
eventCollection.onCombatStart.Invoke();
|
||||
|
||||
foreach (CharacterBase character in characterController.characters)
|
||||
{
|
||||
character.eventSubmodule.onCombatStart.Invoke();
|
||||
foreach (EquipmentBase equipment in character.equipmentSubmodule.currentEquipments)
|
||||
equipment.eventSubmodule.onCombatStart.Invoke();
|
||||
}
|
||||
character.DispatchCombatStart();
|
||||
|
||||
foreach (CardInstance card in characterController.characters
|
||||
.SelectMany(character => character.deckSubmodule.GetAllCards()))
|
||||
{
|
||||
card.eventSubmodule.onCombatStart.Invoke();
|
||||
}
|
||||
// 1.2b — 初始化 CombatLogs 并订阅事件
|
||||
CombatLogs.Instance.Initialize(this);
|
||||
|
||||
NextRound();
|
||||
}
|
||||
|
||||
public void NextRound()
|
||||
{
|
||||
// 战斗已结束则不再推进
|
||||
if (combatState != CombatState.InProgress) return;
|
||||
|
||||
currentRound++;
|
||||
|
||||
// UI 反馈:回合提示动画(同步,纯 UI 无逻辑影响)
|
||||
@@ -108,45 +117,67 @@ namespace Continentis.MainGame.Combat
|
||||
if (intendedCard.targets.Count > 0)
|
||||
{
|
||||
CardInstance card = intendedCard.cardInstance;
|
||||
card.eventSubmodule.onTargeting(intendedCard.targets[0]);
|
||||
card.Targeting(intendedCard.targets[0]);
|
||||
card.contentSubmodule.dirtyMark = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 以下所有事件入队,确保 Buff 触发的视觉效果顺序正确 ────────────
|
||||
// ── 进入"回合前确认"阶段:等待玩家点击 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.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(() => captured.DispatchRoundStart()));
|
||||
}
|
||||
|
||||
// ── 所有回合开始事件处理完毕后,进入第一个行动 ────────────────────
|
||||
CommandQueueManager.Instance.AddCommand(Cmd.Do(NextAction));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 玩家在"回合前确认"阶段点击 Confirm 后调用,释放队列暂停信号。
|
||||
/// </summary>
|
||||
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.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(() => captured.DispatchRoundEnd()));
|
||||
}
|
||||
|
||||
CommandQueueManager.Instance.AddCommand(Cmd.Do(NextRound));
|
||||
@@ -158,15 +189,14 @@ namespace Continentis.MainGame.Combat
|
||||
CharacterBase actionCharacter = currentCharacter;
|
||||
CommandQueueManager.Instance.AddCommand(Cmd.Do(() =>
|
||||
{
|
||||
actionCharacter.eventSubmodule.onActionStart.Invoke();
|
||||
actionCharacter.combatBuffSubmodule.ActionStart();
|
||||
actionCharacter.DispatchActionStart();
|
||||
actionCharacter.recordSubmodule.SetAction(currentRound, ++currentActionIndex);
|
||||
}));
|
||||
|
||||
CombatMainPage combatMainPage = CombatUIManager.Instance.combatMainPage;
|
||||
|
||||
if (currentCharacter is PlayerHero playerHero)
|
||||
{
|
||||
CombatMainPage combatMainPage = CombatUIManager.Instance.combatMainPage;
|
||||
|
||||
playerHero.deckSubmodule.SetUpHandCardViews();
|
||||
combatMainPage.handPile.isUpdatingLayout = false;
|
||||
|
||||
@@ -179,23 +209,24 @@ namespace Continentis.MainGame.Combat
|
||||
}));
|
||||
|
||||
combatMainPage.combatResourcesDisplayer.SetCharacter(playerHero);
|
||||
CombatUIManager.Instance.combatMainPage.endActionButton
|
||||
.GetComponentInChildren<TMP_Text>().text = "End Action";
|
||||
CombatUIManager.Instance.combatMainPage.endActionButton.interactable = true;
|
||||
combatMainPage.SetButtonAction(EndAction, "End Action", true);
|
||||
}
|
||||
else if (currentCharacter is CombatNPC)
|
||||
{
|
||||
if (currentCharacter.fraction == Fraction.Enemy)
|
||||
CombatUIManager.Instance.combatMainPage.endActionButton.GetComponentInChildren<TMP_Text>().text = "Enemy Action";
|
||||
else if (currentCharacter.fraction == Fraction.Ally)
|
||||
CombatUIManager.Instance.combatMainPage.endActionButton.GetComponentInChildren<TMP_Text>().text = "Ally Action";
|
||||
else
|
||||
CombatUIManager.Instance.combatMainPage.endActionButton.GetComponentInChildren<TMP_Text>().text = "Others Action";
|
||||
|
||||
CombatUIManager.Instance.combatMainPage.endActionButton.interactable = false;
|
||||
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;
|
||||
@@ -205,11 +236,15 @@ namespace Continentis.MainGame.Combat
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -221,23 +256,11 @@ namespace Continentis.MainGame.Combat
|
||||
|
||||
public void EndAction()
|
||||
{
|
||||
CombatUIManager.Instance.combatMainPage.endActionButton
|
||||
.GetComponentInChildren<TMP_Text>().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));
|
||||
}
|
||||
CombatUIManager.Instance.combatMainPage.SetButtonAction(null, "Waiting...", false);
|
||||
|
||||
CommandQueueManager.Instance.AddCommand(Cmd.Do(() =>
|
||||
{
|
||||
currentCharacter.combatBuffSubmodule.ActionEnd();
|
||||
currentCharacter.DispatchActionEnd();
|
||||
|
||||
if (currentCharacter is PlayerHero playerHero)
|
||||
{
|
||||
@@ -259,4 +282,73 @@ namespace Continentis.MainGame.Combat
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public partial class CombatMainManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 结束战斗,触发胜负流程。由 CombatCharacterController.CheckCombatEnd() 调用。
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 战斗胜利处理:收集战后英雄 HP,通知 MainGameManager 推进节点并存档。
|
||||
/// </summary>
|
||||
private void CombatVictory()
|
||||
{
|
||||
CombatUIManager.Instance.combatMainPage.SetButtonAction(null, "Victory!", false);
|
||||
|
||||
// 将玩家英雄的战后 HP 与 RunSave 中的 HeroSave 对应:按 currentRun.heroes 顺序匹配
|
||||
var heroResults = new List<(string heroID, int currentHP)>();
|
||||
List<HeroSave> 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)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 战斗失败处理:通知 MainGameManager 删档并返回主菜单。
|
||||
/// </summary>
|
||||
private void CombatDefeat()
|
||||
{
|
||||
CombatUIManager.Instance.combatMainPage.SetButtonAction(null, "Defeat...", false);
|
||||
|
||||
CommandQueueManager.Instance.AddCommand(Cmd.Do(() =>
|
||||
MainGameManager.Instance.ExitCombat(isVictory: false)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user