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 客户端对拍缺陷发现与修复工程指南
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
# system_setting_system.gd —— Metin2 40250 音频视听与战斗选项系统 1:1
|
||||
# 对照 40250 服务端与客户端 PythonSystem.cpp, uisystemoption.py, uigameoption.py
|
||||
class_name SystemSettingSystem
|
||||
extends RefCounted
|
||||
|
||||
signal setting_changed(setting_name: String, new_val: Variant)
|
||||
signal pk_mode_changed(new_mode: int, mode_name: String)
|
||||
|
||||
enum PkMode {
|
||||
PEACE = 0, # 和平
|
||||
REVENGE = 1, # 善恶 (仅可攻击负善恶红名)
|
||||
GUILD = 2, # 阵营 (公会战保护)
|
||||
FREE = 3 # 自由 (无限制)
|
||||
}
|
||||
|
||||
# 音频设置
|
||||
var bgm_volume: float = 0.8:
|
||||
set(v):
|
||||
bgm_volume = clampf(v, 0.0, 1.0)
|
||||
setting_changed.emit("bgm_volume", bgm_volume)
|
||||
|
||||
var sfx_volume: float = 0.8:
|
||||
set(v):
|
||||
sfx_volume = clampf(v, 0.0, 1.0)
|
||||
setting_changed.emit("sfx_volume", sfx_volume)
|
||||
|
||||
var is_muted: bool = false:
|
||||
set(v):
|
||||
is_muted = v
|
||||
setting_changed.emit("is_muted", is_muted)
|
||||
|
||||
# 视距与画质设置
|
||||
var camera_distance: float = 25.0:
|
||||
set(v):
|
||||
camera_distance = clampf(v, 15.0, 40.0)
|
||||
setting_changed.emit("camera_distance", camera_distance)
|
||||
|
||||
var fog_level: int = 1: # 0: 无, 1: 近, 2: 远
|
||||
set(v):
|
||||
fog_level = clampi(v, 0, 2)
|
||||
setting_changed.emit("fog_level", fog_level)
|
||||
|
||||
var shadow_quality: int = 1: # 0: 关, 1: 地面, 2: 全部
|
||||
set(v):
|
||||
shadow_quality = clampi(v, 0, 2)
|
||||
setting_changed.emit("shadow_quality", shadow_quality)
|
||||
|
||||
# 战斗飘字与标签显示
|
||||
var show_damage_dealt: bool = true
|
||||
var show_damage_received: bool = true
|
||||
var show_critical_hit: bool = true
|
||||
var show_monster_names: bool = true
|
||||
var show_player_names: bool = true
|
||||
|
||||
# PK 模式
|
||||
var current_pk_mode: int = PkMode.PEACE
|
||||
|
||||
# 设置 PK 模式
|
||||
func set_pk_mode(mode: int) -> Dictionary:
|
||||
if mode < PkMode.PEACE or mode > PkMode.FREE:
|
||||
return {"ok": false, "reason": "INVALID_PK_MODE", "msg": "无效的 PK 模式!"}
|
||||
|
||||
current_pk_mode = mode
|
||||
var mname := get_pk_mode_name(mode)
|
||||
pk_mode_changed.emit(mode, mname)
|
||||
|
||||
return {
|
||||
"ok": true,
|
||||
"mode": mode,
|
||||
"mode_name": mname,
|
||||
"msg": "PK 模式已切换为【%s】!" % mname
|
||||
}
|
||||
|
||||
# 获取模式中文名称
|
||||
func get_pk_mode_name(mode: int) -> String:
|
||||
match mode:
|
||||
PkMode.PEACE: return "和平模式"
|
||||
PkMode.REVENGE: return "善恶反击模式"
|
||||
PkMode.GUILD: return "阵营公会模式"
|
||||
PkMode.FREE: return "自由对决模式"
|
||||
_: return "未知模式"
|
||||
|
||||
# 判定是否可以对指定目标发起攻击 (PK 判定状态机)
|
||||
func can_attack_target(
|
||||
target_is_player: bool,
|
||||
target_alignment: int = 0,
|
||||
target_guild_id: int = 0,
|
||||
my_guild_id: int = 0
|
||||
) -> bool:
|
||||
# 怪物/NPC 永远可以攻击
|
||||
if not target_is_player:
|
||||
return true
|
||||
|
||||
# 玩家间攻击依据 PK 模式判定
|
||||
match current_pk_mode:
|
||||
PkMode.PEACE:
|
||||
# 和平模式:严禁攻击任何玩家
|
||||
return false
|
||||
|
||||
PkMode.REVENGE:
|
||||
# 善恶模式:只可攻击红名玩家 (善恶值 < 0)
|
||||
return target_alignment < 0
|
||||
|
||||
PkMode.GUILD:
|
||||
# 阵营模式:同公会玩家受到保护,禁止攻击
|
||||
if my_guild_id > 0 and target_guild_id > 0 and my_guild_id == target_guild_id:
|
||||
return false
|
||||
return true
|
||||
|
||||
PkMode.FREE:
|
||||
# 自由模式:可攻击任何玩家
|
||||
return true
|
||||
|
||||
_:
|
||||
return false
|
||||
|
||||
# 导出配置项
|
||||
func export_settings() -> Dictionary:
|
||||
return {
|
||||
"bgm_volume": bgm_volume,
|
||||
"sfx_volume": sfx_volume,
|
||||
"is_muted": is_muted,
|
||||
"camera_distance": camera_distance,
|
||||
"fog_level": fog_level,
|
||||
"shadow_quality": shadow_quality,
|
||||
"show_damage_dealt": show_damage_dealt,
|
||||
"show_damage_received": show_damage_received,
|
||||
"show_critical_hit": show_critical_hit,
|
||||
"show_monster_names": show_monster_names,
|
||||
"show_player_names": show_player_names,
|
||||
"current_pk_mode": current_pk_mode
|
||||
}
|
||||
|
||||
# 导入配置项
|
||||
func import_settings(cfg: Dictionary) -> void:
|
||||
if cfg.has("bgm_volume"): bgm_volume = float(cfg["bgm_volume"])
|
||||
if cfg.has("sfx_volume"): sfx_volume = float(cfg["sfx_volume"])
|
||||
if cfg.has("is_muted"): is_muted = bool(cfg["is_muted"])
|
||||
if cfg.has("camera_distance"): camera_distance = float(cfg["camera_distance"])
|
||||
if cfg.has("fog_level"): fog_level = int(cfg["fog_level"])
|
||||
if cfg.has("shadow_quality"): shadow_quality = int(cfg["shadow_quality"])
|
||||
if cfg.has("show_damage_dealt"): show_damage_dealt = bool(cfg["show_damage_dealt"])
|
||||
if cfg.has("show_damage_received"): show_damage_received = bool(cfg["show_damage_received"])
|
||||
if cfg.has("show_critical_hit"): show_critical_hit = bool(cfg["show_critical_hit"])
|
||||
if cfg.has("show_monster_names"): show_monster_names = bool(cfg["show_monster_names"])
|
||||
if cfg.has("show_player_names"): show_player_names = bool(cfg["show_player_names"])
|
||||
if cfg.has("current_pk_mode"): set_pk_mode(int(cfg["current_pk_mode"]))
|
||||
Reference in New Issue
Block a user