# combat_replay_snapshot_system.gd —— Metin2 40250 战斗高光战报与首领击杀瞬间快照 1:1 # 对照 40250 服务端 battle.cpp, packet.h, char_battle.cpp class_name CombatReplaySnapshotSystem extends RefCounted signal combat_session_started(target_name: String) signal combat_highlight_generated(card: Dictionary) signal new_personal_record(target_name: String, record_type: String, new_val: int) const MAX_STORED_CARDS := 20 var is_in_session: bool = false var session_id: int = 1 var target_vnum: int = 0 var target_name: String = "" var target_max_hp: int = 0 var session_start_time: float = 0.0 var elapsed_time: float = 0.0 var total_damage_dealt: int = 0 var total_damage_taken: int = 0 var total_attacks: int = 0 var total_skills_used: int = 0 var max_single_hit: int = 0 var critical_hits_count: int = 0 # 历史高光战报归档 var highlight_cards: Array = [] # 个人最高纪录:target_name -> { "best_dps": int, "fastest_time": float, "highest_hit": int } var personal_bests: Dictionary = {} # 开始一场战斗记录 func start_combat_session(vnum: int, tname: String, max_hp: int) -> Dictionary: is_in_session = true target_vnum = vnum target_name = tname target_max_hp = max_hp session_start_time = Time.get_unix_time_from_system() elapsed_time = 0.0 total_damage_dealt = 0 total_damage_taken = 0 total_attacks = 0 total_skills_used = 0 max_single_hit = 0 critical_hits_count = 0 combat_session_started.emit(target_name) return { "ok": true, "session_id": session_id, "target_name": target_name, "target_hp": target_max_hp } # 记录一次攻击命中 func record_hit(dmg: int, is_crit: bool, skill_name: String = "") -> void: if not is_in_session: return total_damage_dealt += dmg total_attacks += 1 if is_crit: critical_hits_count += 1 if not skill_name.is_empty(): total_skills_used += 1 if dmg > max_single_hit: max_single_hit = dmg # 记录受到的伤害 func record_damage_taken(dmg: int) -> void: if not is_in_session: return total_damage_taken += dmg # 帧心跳更新战斗时长 func update(delta: float) -> void: if is_in_session: elapsed_time += delta # 结束战斗并生成结构化高光快照战报 func end_combat_session(is_kill: bool, drops: Array = []) -> Dictionary: if not is_in_session: return {"ok": false, "reason": "NO_ACTIVE_SESSION"} is_in_session = false var duration = max(0.5, elapsed_time) var dps = int(float(total_damage_dealt) / duration) # 战斗评级评估 (S / A / B / C) var rank = "C" if is_kill: if dps >= 4000: rank = "S" elif dps >= 2500: rank = "A" elif dps >= 1200: rank = "B" else: rank = "C" var card: Dictionary = { "session_id": session_id, "target_vnum": target_vnum, "target_name": target_name, "is_kill": is_kill, "rank": rank, "duration": duration, "total_damage": total_damage_dealt, "dps": dps, "max_single_hit": max_single_hit, "crit_count": critical_hits_count, "damage_taken": total_damage_taken, "skills_used": total_skills_used, "drops": drops.duplicate(true), "datetime": Time.get_datetime_string_from_system() } session_id += 1 highlight_cards.push_front(card) if highlight_cards.size() > MAX_STORED_CARDS: highlight_cards.pop_back() # 刷新个人纪录判定 _update_personal_bests(card) combat_highlight_generated.emit(card) return card # 检查并更新个人生涯纪录 func _update_personal_bests(card: Dictionary) -> void: if not card["is_kill"]: return var tname: String = card["target_name"] if not personal_bests.has(tname): personal_bests[tname] = { "best_dps": card["dps"], "fastest_time": card["duration"], "highest_hit": card["max_single_hit"] } new_personal_record.emit(tname, "FIRST_KILL", card["dps"]) return var pb = personal_bests[tname] if card["dps"] > pb["best_dps"]: pb["best_dps"] = card["dps"] new_personal_record.emit(tname, "BEST_DPS", card["dps"]) if card["duration"] < pb["fastest_time"]: pb["fastest_time"] = card["duration"] new_personal_record.emit(tname, "FASTEST_TIME", int(card["duration"])) if card["max_single_hit"] > pb["highest_hit"]: pb["highest_hit"] = card["max_single_hit"] new_personal_record.emit(tname, "HIGHEST_HIT", card["max_single_hit"]) # 查询最近战报 func get_recent_highlights() -> Array: return highlight_cards # 查询特定目标的最佳战报纪录 func get_personal_best(tname: String) -> Dictionary: return personal_bests.get(tname, {})