Files
mtgodot-poc/project/title_trophy_buff_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

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()
}