Files
mtgodot-poc/project/dungeon_ranking_system.gd
T
shenandshen 66d217b313 feat(client): 完成40250客户端核心功能1:1对齐与桥梁高度采样修复
- 桥梁与静态物体高度采样修复:
  - 严格对齐 40250 CMapOutdoor::GetHeight 与 CAttributeInstance::GetHeight
  - 解析 .mdatr 中的 AttributeHeight 网格,使用 is_in_triangle_2d 准确计算桥面多边形平面方程
  - sample_height 查询邻近区块并返回 fMAX(fObjectHeight, fTerrainHeight),彻底解决走上桥面穿透掉入水底/河床的问题
  - 新增 test_bridge_height_parity.gd 自动化对拍测试
- 40250 怪物击杀经验动效:
  - 1:1 实现 FLY_EXP(0) / FLY_HP / FLY_SP 粒子轨迹与爆炸吸附
- 40250 客户端全系统功能对齐(Batches 1-31):
  - 包含公会、交易、骑乘、变身、钓鱼、采矿、商城、信件、结婚、地牢等 134 套对拍系统与自动化回归测试
- 文档沉淀:
  - 新增 docs/CLIENT-PARITY-AUDIT-AND-FIX-GUIDE.md 客户端对拍缺陷发现与修复工程指南
2026-09-19 08:51:25 -07:00

134 lines
4.2 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# dungeon_ranking_system.gd —— Metin2 40250 地牢信息面板与最速通关记录系统 1:1
# 对照 40250 服务端与客户端 dungeon_info.cpp, dungeon.cpp, uidungeoninfo.py
class_name DungeonRankingSystem
extends RefCounted
signal record_updated(dungeon_id: String, fastest_time: float, total_clears: int)
signal new_fastest_record(dungeon_id: String, new_time: float, old_time: float)
# 40250 官方经典地牢登记表
const DUNGEON_REGISTRY: Dictionary = {
"demon_tower": {
"name": "恶魔之塔",
"min_level": 40,
"ticket_vnum": 0,
"ticket_count": 0,
"ticket_name": "无",
"cooldown_seconds": 0.0
},
"spider_dungeon_3": {
"name": "蜘蛛洞穴三层",
"min_level": 50,
"ticket_vnum": 30327,
"ticket_count": 1,
"ticket_name": "蜘蛛钥匙",
"cooldown_seconds": 1800.0 # 30 分钟
},
"dragon_lair": {
"name": "冰龙贝兰巢穴",
"min_level": 75,
"ticket_vnum": 30179,
"ticket_count": 3,
"ticket_name": "扭曲钥匙",
"cooldown_seconds": 3600.0 # 60 分钟
},
"devils_catacomb": {
"name": "地下墓穴",
"min_level": 75,
"ticket_vnum": 30311,
"ticket_count": 1,
"ticket_name": "灵魂水晶钥匙",
"cooldown_seconds": 3600.0 # 60 分钟
}
}
# 个人通关数据字典: dungeon_id -> Dictionary
var dungeon_records: Dictionary = {}
func _init() -> void:
for d_id in DUNGEON_REGISTRY.keys():
dungeon_records[d_id] = {
"total_clears": 0,
"fastest_clear_time": 999999.0, # 初始极大值
"highest_peak_damage": 0,
"last_clear_timestamp": 0.0
}
# 记录通关结算
func record_clear(
dungeon_id: String,
clear_time_sec: float,
peak_damage: int,
current_timestamp: float = 0.0
) -> Dictionary:
if not DUNGEON_REGISTRY.has(dungeon_id):
return {"ok": false, "reason": "INVALID_DUNGEON_ID", "msg": "未知的地牢!"}
var rec = dungeon_records[dungeon_id]
rec["total_clears"] += 1
rec["last_clear_timestamp"] = current_timestamp
# 检查并更新最高单次输出伤害
if peak_damage > int(rec["highest_peak_damage"]):
rec["highest_peak_damage"] = peak_damage
# 检查是否刷新最速通关记录
var is_new_record := false
var old_time: float = float(rec["fastest_clear_time"])
if clear_time_sec < old_time:
is_new_record = true
rec["fastest_clear_time"] = clear_time_sec
new_fastest_record.emit(dungeon_id, clear_time_sec, old_time)
record_updated.emit(dungeon_id, rec["fastest_clear_time"], rec["total_clears"])
var dname: String = DUNGEON_REGISTRY[dungeon_id]["name"]
return {
"ok": true,
"dungeon_id": dungeon_id,
"dungeon_name": dname,
"clear_time": clear_time_sec,
"is_new_record": is_new_record,
"fastest_time": rec["fastest_clear_time"],
"total_clears": rec["total_clears"],
"highest_peak_damage": rec["highest_peak_damage"],
"msg": "【%s】通关成功!耗时 %.1f%s" % [dname, clear_time_sec, " (刷新最快纪录!)" if is_new_record else ""]
}
# 获取地牢详情与入场/冷却状态
func get_dungeon_info(dungeon_id: String, current_timestamp: float = 0.0) -> Dictionary:
if not DUNGEON_REGISTRY.has(dungeon_id):
return {"ok": false, "reason": "INVALID_DUNGEON_ID"}
var cfg = DUNGEON_REGISTRY[dungeon_id]
var rec = dungeon_records[dungeon_id]
# 判定冷却时间
var cd_sec: float = float(cfg["cooldown_seconds"])
var last_ts: float = float(rec["last_clear_timestamp"])
var elapsed := current_timestamp - last_ts
var is_on_cooldown := (cd_sec > 0.0 and last_ts > 0.0 and elapsed < cd_sec)
var remaining_cd := maxf(0.0, cd_sec - elapsed) if is_on_cooldown else 0.0
return {
"ok": true,
"dungeon_id": dungeon_id,
"name": cfg["name"],
"min_level": cfg["min_level"],
"ticket_vnum": cfg["ticket_vnum"],
"ticket_count": cfg["ticket_count"],
"ticket_name": cfg["ticket_name"],
"is_on_cooldown": is_on_cooldown,
"remaining_cooldown": remaining_cd,
"total_clears": rec["total_clears"],
"fastest_clear_time": rec["fastest_clear_time"] if rec["fastest_clear_time"] < 999999.0 else 0.0,
"highest_peak_damage": rec["highest_peak_damage"]
}
# 获取全部地牢摘要速览列表
func get_all_dungeon_summaries(current_timestamp: float = 0.0) -> Array:
var list: Array = []
for d_id in DUNGEON_REGISTRY.keys():
list.append(get_dungeon_info(d_id, current_timestamp))
return list