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

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)