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

148 lines
4.5 KiB
GDScript

# 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"]))