- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
174 lines
5.4 KiB
GDScript
174 lines
5.4 KiB
GDScript
# title_trophy_buff_system.gd —— Metin2 40250 真实称号词条战力加成与奖杯成就图鉴 1:1
|
|
# 对照 40250 服务端 affect.h, cmd_general.cpp, title.cpp, char_affect.cpp
|
|
class_name TitleTrophyBuffSystem
|
|
extends RefCounted
|
|
|
|
signal trophy_milestone_reached(tier: int, trophy_name: String, bonus_desc: String)
|
|
signal title_stat_buffs_applied(title_name: String, buffs: Dictionary)
|
|
signal title_stat_buffs_removed(title_name: String)
|
|
|
|
# 经典称号与专属真实战力词条池
|
|
const TITLES_CATALOG: Dictionary = {
|
|
"屠龙尊者": {
|
|
"desc": "贝雷斯水龙终结者,威震天界之峰",
|
|
"buffs": {
|
|
"boss_dmg_pct": 15,
|
|
"max_hp": 2000,
|
|
"crit_pct": 5
|
|
}
|
|
},
|
|
"恶魔克星": {
|
|
"desc": "诛灭死神与阿兹瑞尔,冥府幽界之灾",
|
|
"buffs": {
|
|
"undead_dmg_pct": 15,
|
|
"magic_resist": 10,
|
|
"def": 60
|
|
}
|
|
},
|
|
"魔石终结者": {
|
|
"desc": "踏平八荒八档魔石,破除虚空陨铁",
|
|
"buffs": {
|
|
"metin_dmg_pct": 12,
|
|
"atk": 50,
|
|
"penetration_pct": 5
|
|
}
|
|
},
|
|
"地牢速通王": {
|
|
"desc": "创下各大地牢副本最速纪录的疾风勇者",
|
|
"buffs": {
|
|
"move_speed": 15,
|
|
"cast_speed": 10,
|
|
"max_sp": 1000
|
|
}
|
|
},
|
|
"百战名将": {
|
|
"desc": "力克四大野外世界首领,声震三界",
|
|
"buffs": {
|
|
"atk": 80,
|
|
"def": 50,
|
|
"max_hp": 1500
|
|
}
|
|
},
|
|
"商海巨擘": {
|
|
"desc": "富甲一方,日进斗金的广场交易领主",
|
|
"buffs": {
|
|
"gold_bonus_pct": 20,
|
|
"max_hp": 500
|
|
}
|
|
},
|
|
"武学至尊": {
|
|
"desc": "多门绝技臻至 P 级圆满的盖世宗师",
|
|
"buffs": {
|
|
"skill_dmg_pct": 10,
|
|
"cast_speed": 15,
|
|
"atk": 60
|
|
}
|
|
}
|
|
}
|
|
|
|
# 奖杯累积成就里程碑 (永久被动战力加成)
|
|
const TROPHY_MILESTONES: Dictionary = {
|
|
1: {"pts": 50, "name": "青铜试炼奖杯", "bonus": {"all_stats": 3}, "desc": "全属性 +3"},
|
|
2: {"pts": 150, "name": "白银征服奖杯", "bonus": {"max_hp": 1000, "drop_rate_pct": 5}, "desc": "生命上限 +1000,掉宝率 +5%"},
|
|
3: {"pts": 300, "name": "黄金霸主奖杯", "bonus": {"atk": 50, "crit_pct": 5}, "desc": "攻击力 +50,暴击率 +5%"},
|
|
4: {"pts": 500, "name": "铂金封神奖杯", "bonus": {"boss_dmg_pct": 10, "exp_bonus_pct": 10}, "desc": "首领伤害 +10%,经验获取 +10%"}
|
|
}
|
|
|
|
var active_title: String = ""
|
|
var active_title_buffs: Dictionary = {}
|
|
var unlocked_titles: Array = []
|
|
var trophy_points: int = 0
|
|
var reached_milestones: Array = []
|
|
|
|
# 解锁新称号
|
|
func unlock_title(title_name: String, awarded_points: int = 50) -> Dictionary:
|
|
if not TITLES_CATALOG.has(title_name):
|
|
return {"ok": false, "reason": "UNKNOWN_TITLE", "msg": "未知的称号!"}
|
|
|
|
if not (title_name in unlocked_titles):
|
|
unlocked_titles.append(title_name)
|
|
trophy_points += awarded_points
|
|
_check_trophy_milestones()
|
|
return {"ok": true, "title": title_name, "points": trophy_points, "msg": "解锁了殿堂称号【%s】!" % title_name}
|
|
|
|
return {"ok": true, "already_unlocked": true, "title": title_name}
|
|
|
|
# 佩戴指定称号并动态注入角色属性面板
|
|
func equip_title(title_name: String, player_data: Dictionary) -> Dictionary:
|
|
if not (title_name in unlocked_titles):
|
|
return {"ok": false, "reason": "TITLE_NOT_UNLOCKED", "msg": "尚未解锁该称号!"}
|
|
|
|
# 先卸下旧称号属性
|
|
if not active_title.is_empty():
|
|
_remove_title_buffs(player_data)
|
|
|
|
active_title = title_name
|
|
var cfg = TITLES_CATALOG[title_name]
|
|
active_title_buffs = cfg["buffs"].duplicate(true)
|
|
|
|
_apply_buffs_to_player(player_data, active_title_buffs)
|
|
title_stat_buffs_applied.emit(active_title, active_title_buffs)
|
|
|
|
return {
|
|
"ok": true,
|
|
"title": active_title,
|
|
"buffs": active_title_buffs,
|
|
"msg": "已佩戴称号【%s】!获得了专属战力加成。" % active_title
|
|
}
|
|
|
|
# 卸下当前称号
|
|
func unequip_title(player_data: Dictionary) -> Dictionary:
|
|
if active_title.is_empty():
|
|
return {"ok": false, "reason": "NO_TITLE_EQUIPPED"}
|
|
|
|
var old = active_title
|
|
_remove_title_buffs(player_data)
|
|
active_title = ""
|
|
active_title_buffs.clear()
|
|
|
|
title_stat_buffs_removed.emit(old)
|
|
|
|
return {"ok": true, "msg": "已卸下称号【%s】。" % old}
|
|
|
|
# 将 Buff 加成数值安全叠加入 player_data
|
|
func _apply_buffs_to_player(player_data: Dictionary, buffs: Dictionary) -> void:
|
|
for stat_key in buffs.keys():
|
|
var val = buffs[stat_key]
|
|
player_data[stat_key] = player_data.get(stat_key, 0) + val
|
|
|
|
# 从 player_data 中精准反扣旧 Buff 加成数值
|
|
func _remove_title_buffs(player_data: Dictionary) -> void:
|
|
for stat_key in active_title_buffs.keys():
|
|
var val = active_title_buffs[stat_key]
|
|
player_data[stat_key] = player_data.get(stat_key, 0) - val
|
|
|
|
# 检测奖杯里程碑晋阶
|
|
func _check_trophy_milestones() -> void:
|
|
for tier in [1, 2, 3, 4]:
|
|
if not (tier in reached_milestones):
|
|
var req = TROPHY_MILESTONES[tier]["pts"]
|
|
if trophy_points >= req:
|
|
reached_milestones.append(tier)
|
|
var m = TROPHY_MILESTONES[tier]
|
|
trophy_milestone_reached.emit(tier, m["name"], m["desc"])
|
|
|
|
# 获取所有奖杯被动被动加成总计
|
|
func get_total_trophy_passive_bonuses() -> Dictionary:
|
|
var total: Dictionary = {}
|
|
for tier in reached_milestones:
|
|
var b = TROPHY_MILESTONES[tier]["bonus"]
|
|
for k in b.keys():
|
|
total[k] = total.get(k, 0) + b[k]
|
|
return total
|
|
|
|
# 获取当前全部战力属性摘要
|
|
func get_title_status() -> Dictionary:
|
|
return {
|
|
"active_title": active_title,
|
|
"active_buffs": active_title_buffs,
|
|
"unlocked_count": unlocked_titles.size(),
|
|
"trophy_points": trophy_points,
|
|
"reached_milestones": reached_milestones,
|
|
"passive_bonuses": get_total_trophy_passive_bonuses()
|
|
}
|