Files

273 lines
9.7 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# HelpUI (P11 / §8.3) —— 游戏内帮助窗(1:1 迁移 `assets/root/uihelp.py` 的
# `HelpWindow`,单页版:`ENABLE_HELP_MULTIPAGE = 0` → `LoadDialogSinglePage()`)。
#
# var hw := preload("res://ui/help_ui.gd").new()
# add_child(hw)
# hw.setup(ui_manager, m2client, assets_root)
# hw.toggle() # H 键(非 Ctrl
# hw.open() # ESC 系统菜单 help_button
#
# 布局走真 `assets/uiscript/uiscript/helpwindow.py`UiScript → UiBuild)。
# 文本逐字对齐 `uiScriptLocale.HELP_*``locale/locale/<lang>/locale_interface.txt`);
# `ui_manager` 没接 locale 回调时,`helpwindow.py` 里的 `uiScriptLocale.X` 会被
# UiScript 解析成 `<X>` 占位,`_relabel()` 再用本工程的 `Locale` 表 + 英文兜底补回。
#
# 入口逐字对照 `game.py:459 __PressHKey()`:非 Ctrl → `interface.OpenHelpWindow()`
# Ctrl+H 是 `net.SendChatPacket("/user_horse_ride")`,不在本窗职责内)。
# 关闭对照 `helpwindow.py` 的 `HelpWindow``close_button` / `OnPressEscapeKey` /
# `OnPressExitKey` / `OnKeyDown(DIK_H)` 都调用 `eventClose`。ESC 由 `UiManager`
# 的窗口栈统一处理(关最顶层);H 键复用 `toggle()`。
extends Node
const MobileTouchButton = preload("res://ui/mobile/mobile_touch_button.gd")
# helpwindow.py 的 name → uiScriptLocale key(逐字,含原脚本里重名的两个 `help_02`)。
const FLOAT_ROWS := {
"help_01": "HELP_MOVE_KEY",
"help_02": "HELP_CONTROL_CAMERA_BY_MIDDLEBUTTON", # 原脚本第二个 help_02(后者覆盖)
"help_03": "HELP_SHOW_ALL_NAME",
"help_04": "HELP_OPEN_CHAT",
"help_05": "HELP_OPEN_WHISPER",
"help_06": "HELP_ATTACK_KEY",
"help_07": "HELP_OPEN_CHARACTER",
"help_08": "HELP_OPEN_SKILL",
"help_09": "HELP_OPEN_QUEST",
"help_10": "HELP_OPEN_INVENTORY",
"help_11": "HELP_OPEN_LOG",
"help_12": "HELP_OPEN_ZONEMAP",
"help_13": "HELP_OPEN_MINIMAP",
"help_14": "HELP_CHANGE_PK_MODE",
"help_15": "HELP_PICK_ITEM",
"help_16": "HELP_SCREEN_CAPTURE",
"help_17": "HELP_GUILD_WINDOW",
"help_18": "HELP_MESSENGER_WINDOW",
"help_19": "HELP_HELP",
}
# 任务栏贴纸标签(helpwindow.py 的 `taskbar_help_*` 文本)。
const TASKBAR_ROWS := {
"taskbar_help_01": "HELP_FURY",
"taskbar_help_02": "HELP_HP",
"taskbar_help_03": "HELP_SP",
"taskbar_help_04": "HELP_EXP",
"taskbar_help_05": "HELP_MOUSE_LEFT",
"taskbar_help_06": "HELP_MOUSE_RIGHT",
"taskbar_help_07": "HELP_QUICKSLOT",
"taskbar_help_08a": "HELP_SYSTEM_BUTTON",
"taskbar_help_08b": "HELP_CHARACTER_BUTTON1",
"taskbar_help_08c": "HELP_CHARACTER_BUTTON2",
}
# uiScriptLocale 兜底(逐字取自 `locale/locale/en/locale_interface.txt`)——
# 资产缺 locale 表或 UiManager 没接 locale 回调时用这份。
const FALLBACK := {
"HELP_MOVE_KEY": "Panel: W, A, S, D or arrow keys",
"HELP_CONTROL_CAMERA_BY_RIGHTBUTTON": "Camera View: right or middle mouse button",
"HELP_CONTROL_CAMERA_BY_MIDDLEBUTTON": "Camera View: middle or right mouse button",
"HELP_SHOW_ALL_NAME": "Display Names: Alt",
"HELP_OPEN_CHAT": "Open chat window: Enter",
"HELP_OPEN_WHISPER": "Open Whisper Window: Shift + Enter",
"HELP_ATTACK_KEY": "Attack: left mouse button or space bar",
"HELP_OPEN_CHARACTER": "Open character window: C",
"HELP_OPEN_SKILL": "Open Skill Window: V",
"HELP_OPEN_QUEST": "Open Task Window: N",
"HELP_OPEN_INVENTORY": "Open inventory window: I",
"HELP_OPEN_LOG": "Open Chatlog: L",
"HELP_OPEN_ZONEMAP": "Open Large Map: M",
"HELP_OPEN_MINIMAP": "Open mini map: Shift + M",
"HELP_CHANGE_PK_MODE": "Change attack mode: change setting of left mouse button",
"HELP_PICK_ITEM": "Collect Items: ^ or Y or left mouse button",
"HELP_SCREEN_CAPTURE": "Save Screenshot: Print (will be saved in file \"Metin2\\screenshot\")",
"HELP_GUILD_WINDOW": "Open Guild Window: Alt + G",
"HELP_MESSENGER_WINDOW": "Open Friends List: Alt + M",
"HELP_HELP": "Display help: H",
"HELP_FURY": "Ingame Item Shop",
"HELP_HP": "Hit Points (HP)",
"HELP_SP": "Spell Points (SP)",
"HELP_EXP": "Experience",
"HELP_MOUSE_LEFT": "Function of the Left Mouse button",
"HELP_MOUSE_RIGHT": "Function of the Right Mouse button",
"HELP_QUICKSLOT": "Fast Access Fields",
"HELP_SYSTEM_BUTTON": "System buttons",
"HELP_CHARACTER_BUTTON1": "(Character Window, Inventory Window,",
"HELP_CHARACTER_BUTTON2": "List of Friends and Options)",
"CLOSE": "Close",
}
var ui: CanvasLayer
var client: Node
var assets_root := ""
var uiscript_dir := ""
var _win: Dictionary = {}
var _loc # Localeres://locale.gd
var _mobile_mode := false
var _mobile_root: Control
var _mobile_labels: Array[Label] = []
func setup(ui_manager: CanvasLayer, m2client: Node = null, assets := "") -> void:
ui = ui_manager
client = m2client
assets_root = assets
if assets_root == "" and ui and "assets_root" in ui:
assets_root = ui.assets_root
uiscript_dir = assets_root.path_join("uiscript/uiscript")
if not DirAccess.dir_exists_absolute(uiscript_dir):
uiscript_dir = assets_root.path_join("uiscript")
var LocaleScript = load("res://locale.gd")
if LocaleScript:
_loc = LocaleScript.new()
_loc.setup(assets_root, "en")
# --- open / close ---------------------------------------------------
func is_open() -> bool:
if _mobile_mode:
return _mobile_root != null and is_instance_valid(_mobile_root)
return not _win.is_empty() and is_instance_valid(_win.get("root"))
func set_mobile_mode(enabled: bool) -> void:
if not enabled and _mobile_root != null:
var old_mode := _mobile_mode
_mobile_mode = true
close()
_mobile_mode = old_mode
_mobile_mode = enabled
func toggle() -> void:
if is_open(): close()
else: open()
func close() -> void:
if _mobile_mode:
if _mobile_root and is_instance_valid(_mobile_root) and ui:
ui.close(_mobile_root)
_mobile_root = null
_mobile_labels.clear()
return
if is_open():
ui.close(_win["root"])
_win = {}
func open() -> void:
if _mobile_mode:
_open_mobile()
return
if is_open():
return
var path := uiscript_dir.path_join("helpwindow.py")
if not FileAccess.file_exists(path):
push_warning("HelpUI: no helpwindow.py at " + path)
return
_win = ui.open_script(path, assets_root)
if not is_open():
return
_relabel()
_wire()
func _open_mobile() -> void:
if is_open():
return
_mobile_root = Control.new()
_mobile_root.name = "MobileHelpWindow"
_mobile_root.size = Vector2(760, 340)
_mobile_root.set_meta("mobile_title", "帮助")
_mobile_root.mouse_filter = Control.MOUSE_FILTER_STOP
var panel := Panel.new()
panel.set_anchors_preset(Control.PRESET_FULL_RECT)
panel.add_theme_stylebox_override("panel", _mobile_panel_style())
_mobile_root.add_child(panel)
var scroll := ScrollContainer.new()
scroll.position = Vector2(14, 48)
scroll.size = Vector2(732, 278)
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
scroll.mouse_filter = Control.MOUSE_FILTER_STOP
_mobile_root.add_child(scroll)
var list := VBoxContainer.new()
list.custom_minimum_size = Vector2(710, 0)
list.add_theme_constant_override("separation", 4)
scroll.add_child(list)
_mobile_labels.clear()
for key in FLOAT_ROWS.values():
var row := Label.new()
row.text = "• " + _text(String(key))
row.custom_minimum_size = Vector2(700, 28)
row.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
row.add_theme_font_size_override("font_size", 13)
row.add_theme_color_override("font_color", Color(0.82, 0.9, 1.0))
list.add_child(row)
_mobile_labels.append(row)
var task_hint := Label.new()
task_hint.text = "\n" + _text("HELP_QUICKSLOT") + " · " + _text("HELP_SYSTEM_BUTTON")
task_hint.add_theme_font_size_override("font_size", 11)
task_hint.add_theme_color_override("font_color", Color(0.66, 0.76, 0.9))
list.add_child(task_hint)
ui.open(_mobile_root)
func _node(nm: String) -> Control:
if _win.is_empty():
return null
var n = _win.get("nodes", {}).get(nm, null)
return n if n is Control else null
# --- content (uihelp.py.LoadDialogSinglePage + helpwindow.py 文本) ---------
# 解析 `<KEY>` 占位 / 应用 name→key 映射:先扫所有 Label(覆盖原脚本重名的两个
# `help_02`),再按映射兜一遍(nodes dict 只留最后一个同名)。
func _relabel() -> void:
var root: Control = _win.get("root")
if root:
for lbl in root.find_children("*", "Label", true, false):
var t := String(lbl.text)
if t.length() >= 2 and t.begins_with("<") and t.ends_with(">"):
lbl.text = _text(t.substr(1, t.length() - 2))
for nm in FLOAT_ROWS:
_set_text(nm, _text(FLOAT_ROWS[nm]))
for nm in TASKBAR_ROWS:
_set_text(nm, _text(TASKBAR_ROWS[nm]))
_set_text("close_button", _text("CLOSE"))
func _set_text(nm: String, s: String) -> void:
var n := _node(nm)
if n == null:
return
if n.has_method("set_text"):
n.set_text(s)
elif "text" in n:
n.text = s
# uiScriptLocale.<key> 的取值:优先本工程 Locale 表,否则英文兜底,否则原样 key。
func _text(key: String) -> String:
if _loc != null and _loc.has(key):
return _loc.t(key)
return FALLBACK.get(key, key)
# 已绑定的帮助行文本(供自检 / 调试)。
func rows() -> Array:
if _mobile_mode:
var mobile_rows: Array = []
for key in FLOAT_ROWS.values():
mobile_rows.append(_text(String(key)))
return mobile_rows
var out: Array = []
for nm in FLOAT_ROWS:
var n := _node(nm)
if n and "text" in n:
out.append(String(n.text))
return out
# --- wiring (uihelp.py.HelpWindow.SetCloseEvent) ------------------------
func _wire() -> void:
var btn := _node("close_button")
if btn is BaseButton:
btn.pressed.connect(close)
# helpwindow.py2 的多页按钮在单页版不存在;此处不绑。
func _mobile_panel_style() -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = Color(0.04, 0.065, 0.1, 0.98)
style.border_color = Color(0.52, 0.68, 0.9, 0.86)
style.set_border_width_all(1)
style.set_corner_radius_all(8)
return style