using System; using System.Collections.Generic; using System.Text; using Continentis.MainGame.Card; using Continentis.MainGame.Character; using SLSUtilities.General; using UnityEngine; namespace Continentis.MainGame.Combat { public enum CombatLogType { RoundStart, ActionStart, Attack, BuffApply, BuffRemove, CardPlay, Death } public class CombatLogEntry { public int round; public int actionIndex; public float timestamp; public CombatLogType type; public string message; public Dictionary 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(); } } /// /// 战斗日志系统:记录战斗中的关键事件,支持查询与格式化输出。 /// 挂载在战斗场景的 CombatMainManager 同级或子对象上。 /// public class CombatLogs : Singleton { private const string LogPrefix = "[CombatLog]"; private readonly List allEntries = new List(); private CombatMainManager combatManager; // ── 初始化与事件订阅 ────────────────────────────────────────────── /// /// 由 CombatMainManager.StartCombat() 调用,订阅全局及各角色事件。 /// 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(LogDeath, 0)); } /// 为单个角色订阅攻击完成事件(可供动态加入战场的角色调用)。 public void SubscribeCharacterEvents(CharacterBase character) { CharacterBase captured = character; character.eventSubmodule.onFinishAttack.InsertByPriority( "CombatLogs_FinishAttack", new PrioritizedAction( (target, result) => LogAttack(result), 0)); } // ── 日志写入 API ────────────────────────────────────────────────── /// 记录攻击结果。 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); } /// 记录 Buff 施加事件。 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); } /// 记录 Buff 移除事件。 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); } /// 记录卡牌使用事件。 public void LogCardPlay(CardInstance card, List 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); } /// 记录角色死亡事件。 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); } /// 记录回合开始事件。 public void LogRoundStart(int round) { string msg = $"── 第 {round} 回合开始 ──"; var entry = new CombatLogEntry(round, 0, CombatLogType.RoundStart, msg); WriteEntry(entry); } // ── 查询 API ────────────────────────────────────────────────────── /// 按类型和数量查询日志条目。 public List Query(CombatLogType type, int lastN = 10) { var result = new List(); 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; } /// 获取所有日志条目。 public IReadOnlyList GetAllEntries() => allEntries; // ── 格式化 ──────────────────────────────────────────────────────── /// 将条目格式化为人类可读字符串。 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)}"); } } }