- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
180 lines
6.6 KiB
GDScript
180 lines
6.6 KiB
GDScript
# privilege_empire_guild_system.gd —— Metin2 40250 官方帝国与公会恩泽特权倍率系统 1:1
|
|
# 100% 对照 40250 服务端 priv_manager.cpp, priv_manager.h, constants.cpp (c_apszPrivNames)
|
|
class_name PrivilegeEmpireGuildSystem
|
|
extends RefCounted
|
|
|
|
signal empire_privilege_granted(empire: int, priv_type: int, value: int, duration: float)
|
|
signal guild_privilege_granted(guild_id: int, priv_type: int, value: int, duration: float)
|
|
signal character_privilege_granted(player_id: int, priv_type: int, value: int)
|
|
signal privilege_expired(level_type: String, target_id: int, priv_type: int)
|
|
|
|
# 40250 官方特权类别常数
|
|
const PRIV_ITEM_DROP := 1 # 物品掉落率加成 (아이템 드롭 확률)
|
|
const PRIV_GOLD_DROP := 2 # 金币掉落率加成 (돈 드롭 확률)
|
|
const PRIV_GOLD10_DROP := 3 # 暴发大金币堆掉率加成 (돈 폭풍 드롭 확률)
|
|
const PRIV_EXP := 4 # 杀怪经验值倍率加成 (경험치 배율)
|
|
|
|
const PRIV_NAMES: Dictionary = {
|
|
PRIV_ITEM_DROP: "物品爆率加成",
|
|
PRIV_GOLD_DROP: "金币掉落加成",
|
|
PRIV_GOLD10_DROP: "黄金风暴大金币爆率",
|
|
PRIV_EXP: "经验值倍率加成"
|
|
}
|
|
|
|
# 帝国定义 (0 为全服所有帝国)
|
|
const EMPIRE_ALL := 0
|
|
const EMPIRE_SHINSOO := 1
|
|
const EMPIRE_CHUNJO := 2
|
|
const EMPIRE_JINNO := 3
|
|
|
|
# 数据结构:
|
|
# _empire_privs[type][empire] -> {"value": int, "time_remaining": float}
|
|
var _empire_privs: Dictionary = {}
|
|
# _guild_privs[type][guild_id] -> {"value": int, "time_remaining": float}
|
|
var _guild_privs: Dictionary = {}
|
|
# _char_privs[type][player_id] -> int
|
|
var _char_privs: Dictionary = {}
|
|
|
|
func _init() -> void:
|
|
for t in [PRIV_ITEM_DROP, PRIV_GOLD_DROP, PRIV_GOLD10_DROP, PRIV_EXP]:
|
|
_empire_privs[t] = {}
|
|
_guild_privs[t] = {}
|
|
_char_privs[t] = {}
|
|
for emp in [0, 1, 2, 3]:
|
|
_empire_privs[t][emp] = {"value": 0, "time_remaining": 0.0}
|
|
|
|
# ==========================================
|
|
# 1. 设置特权 (GiveEmpirePriv, GiveGuildPriv, GiveCharacterPriv)
|
|
# ==========================================
|
|
|
|
# 设置帝国全域特权 (empire: 0 为全服, 1~3 为指定帝国)
|
|
func set_empire_privilege(empire: int, priv_type: int, value_percent: int, duration_sec: float) -> void:
|
|
if not _is_valid_priv_type(priv_type) or empire < 0 or empire > 3:
|
|
return
|
|
|
|
var val = clamp(value_percent, 0, 1000)
|
|
var dur = max(0.0, duration_sec)
|
|
_empire_privs[priv_type][empire] = {"value": val, "time_remaining": dur}
|
|
empire_privilege_granted.emit(empire, priv_type, val, dur)
|
|
|
|
# 设置公会专属特权
|
|
func set_guild_privilege(guild_id: int, priv_type: int, value_percent: int, duration_sec: float) -> void:
|
|
if not _is_valid_priv_type(priv_type) or guild_id <= 0:
|
|
return
|
|
|
|
var val = clamp(value_percent, 0, 1000)
|
|
var dur = max(0.0, duration_sec)
|
|
_guild_privs[priv_type][guild_id] = {"value": val, "time_remaining": dur}
|
|
guild_privilege_granted.emit(guild_id, priv_type, val, dur)
|
|
|
|
# 设置个人永久/专属特权
|
|
func set_character_privilege(player_id: int, priv_type: int, value_percent: int) -> void:
|
|
if not _is_valid_priv_type(priv_type) or player_id <= 0:
|
|
return
|
|
_char_privs[priv_type][player_id] = value_percent
|
|
character_privilege_granted.emit(player_id, priv_type, value_percent)
|
|
|
|
# ==========================================
|
|
# 2. 移除特权 (RemoveEmpirePriv, RemoveGuildPriv, RemoveCharacterPriv)
|
|
# ==========================================
|
|
func remove_empire_privilege(empire: int, priv_type: int) -> void:
|
|
if _empire_privs.has(priv_type) and _empire_privs[priv_type].has(empire):
|
|
_empire_privs[priv_type][empire] = {"value": 0, "time_remaining": 0.0}
|
|
|
|
func remove_guild_privilege(guild_id: int, priv_type: int) -> void:
|
|
if _guild_privs.has(priv_type):
|
|
_guild_privs[priv_type].erase(guild_id)
|
|
|
|
func remove_character_privilege(player_id: int, priv_type: int) -> void:
|
|
if _char_privs.has(priv_type):
|
|
_char_privs[priv_type].erase(player_id)
|
|
|
|
# ==========================================
|
|
# 3. 特权倍率综合计算 (priv_manager.cpp: GetPriv)
|
|
# ==========================================
|
|
func get_effective_privilege(
|
|
player_id: int,
|
|
empire: int,
|
|
guild_id: int,
|
|
priv_type: int,
|
|
has_exp_ring: bool = false,
|
|
has_thief_glove: bool = false
|
|
) -> int:
|
|
if not _is_valid_priv_type(priv_type):
|
|
return 0
|
|
|
|
# 40250 官方逻辑:
|
|
# 个人特权
|
|
var val_ch: int = _char_privs[priv_type].get(player_id, 0)
|
|
|
|
# 全服全境特权 (Empire 0)
|
|
var val_emp_all = 0
|
|
if _empire_privs[priv_type].has(0) and _empire_privs[priv_type][0]["time_remaining"] > 0.0:
|
|
val_emp_all = int(_empire_privs[priv_type][0]["value"])
|
|
|
|
# 专属帝国特权
|
|
var val_emp = 0
|
|
if _empire_privs[priv_type].has(empire) and _empire_privs[priv_type][empire]["time_remaining"] > 0.0:
|
|
val_emp = int(_empire_privs[priv_type][empire]["value"])
|
|
|
|
# 公会特权
|
|
var val_guild = 0
|
|
if guild_id > 0 and _guild_privs[priv_type].has(guild_id):
|
|
if _guild_privs[priv_type][guild_id]["time_remaining"] > 0.0:
|
|
val_guild = int(_guild_privs[priv_type][guild_id]["value"])
|
|
|
|
# 40250 官方取四者最大加成值 (MAX)
|
|
var max_bonus = max(val_ch, max(val_emp_all, max(val_emp, val_guild)))
|
|
|
|
# 装备道具额外叠加: 经验指环 (70024: 经验 +50%), 小偷手套 (70003: 爆率 +100%)
|
|
if priv_type == PRIV_EXP and has_exp_ring:
|
|
max_bonus += 50
|
|
elif priv_type == PRIV_ITEM_DROP and has_thief_glove:
|
|
max_bonus += 100
|
|
|
|
return max_bonus
|
|
|
|
# ==========================================
|
|
# 4. 心跳更新与倒计时自然失效
|
|
# ==========================================
|
|
func update(delta: float) -> void:
|
|
for t in [PRIV_ITEM_DROP, PRIV_GOLD_DROP, PRIV_GOLD10_DROP, PRIV_EXP]:
|
|
# 帝国特权
|
|
for emp in [0, 1, 2, 3]:
|
|
var ep = _empire_privs[t][emp]
|
|
if ep["time_remaining"] > 0.0:
|
|
ep["time_remaining"] -= delta
|
|
if ep["time_remaining"] <= 0.0:
|
|
ep["time_remaining"] = 0.0
|
|
ep["value"] = 0
|
|
privilege_expired.emit("empire", emp, t)
|
|
|
|
# 公会特权
|
|
var to_erase_guilds: Array[int] = []
|
|
for gid in _guild_privs[t].keys():
|
|
var gp = _guild_privs[t][gid]
|
|
if gp["time_remaining"] > 0.0:
|
|
gp["time_remaining"] -= delta
|
|
if gp["time_remaining"] <= 0.0:
|
|
to_erase_guilds.append(gid)
|
|
|
|
for gid in to_erase_guilds:
|
|
_guild_privs[t].erase(gid)
|
|
privilege_expired.emit("guild", gid, t)
|
|
|
|
func _is_valid_priv_type(t: int) -> bool:
|
|
return t >= PRIV_ITEM_DROP and t <= PRIV_EXP
|
|
|
|
# 序列化与反序列化
|
|
func serialize() -> Dictionary:
|
|
return {
|
|
"empire_privs": _empire_privs.duplicate(true),
|
|
"guild_privs": _guild_privs.duplicate(true),
|
|
"char_privs": _char_privs.duplicate(true)
|
|
}
|
|
|
|
func deserialize(data: Dictionary) -> void:
|
|
_empire_privs = data.get("empire_privs", {}).duplicate(true)
|
|
_guild_privs = data.get("guild_privs", {}).duplicate(true)
|
|
_char_privs = data.get("char_privs", {}).duplicate(true)
|