fix: 装备属性面板避让逻辑 + 多项功能更新

- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧
- inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域
- 包含其他累积的功能开发和测试文件
This commit is contained in:
shen
2026-09-21 16:38:59 -07:00
parent 1522a8a1a1
commit c93894313a
5498 changed files with 4558004 additions and 1442 deletions
+67 -5
View File
@@ -10,6 +10,7 @@
extends Node
const Locale = preload("res://locale.gd")
const WhisperChatSystem = preload("res://whisper_chat_system.gd")
# EChatType (wire.h)
const T_TALKING := 0
@@ -19,6 +20,15 @@ const T_PARTY := 3
const T_GUILD := 4
const T_SHOUT := 6
const T_WHISPER := 7
# PythonChat.h::EWhisperType (40250). Keep these distinct from EChatType:
# 1..4 are server error modes, 5 is GM, and 0xff is a system message.
const WHISPER_TYPE_CHAT := 0
const WHISPER_TYPE_NOT_EXIST := 1
const WHISPER_TYPE_TARGET_BLOCKED := 2
const WHISPER_TYPE_SENDER_BLOCKED := 3
const WHISPER_TYPE_ERROR := 4
const WHISPER_TYPE_GM := 5
const WHISPER_TYPE_SYSTEM := 255
const FISHING_SUCCESS := 3
const FISHING_FAIL := 4
const FISHING_FISH := 5
@@ -50,11 +60,18 @@ var _fishing_active := false
var _whisper_dialog: Panel
var _whisper_target: LineEdit
var _whisper_message: LineEdit
var _whisper_system: RefCounted
var _mobile_mode := false
var _tab_row: HBoxContainer
func setup(m2client: Node, parent: Node, assets_root := "") -> void:
client = m2client
var player_name := "Hero"
if client and client.has_method("get_main_vid") and client.has_method("get_entity"):
var main: Dictionary = client.get_entity(int(client.get_main_vid()))
if not main.is_empty() and not String(main.get("name", "")).is_empty():
player_name = String(main.get("name", "Hero"))
_whisper_system = WhisperChatSystem.new(player_name)
if assets_root != "":
_locale = Locale.new()
_locale.setup(assets_root, "en")
@@ -115,6 +132,8 @@ func start_whisper(name: String) -> void:
if _whisper_dialog == null or name.strip_edges() == "":
return
_whisper_target.text = name.strip_edges()
if _whisper_system:
_whisper_system.open_conversation(_whisper_target.text)
_whisper_message.clear()
_whisper_dialog.visible = true
if _whisper_message.is_inside_tree():
@@ -126,6 +145,14 @@ func is_whisper_open() -> bool:
func whisper_target() -> String:
return _whisper_target.text if _whisper_target != null else ""
func whisper_system() -> RefCounted:
return _whisper_system
func toggle_whisper_ignore(name: String) -> bool:
if _whisper_system == null:
return false
return _whisper_system.toggle_ignore_target(name.strip_edges())
func is_typing() -> bool:
return _input != null and _input.has_focus()
@@ -345,6 +372,8 @@ func _on_whisper_submit(text: String) -> void:
if to == "" or msg == "" or client == null:
return
client.whisper(to, msg)
if _whisper_system:
_whisper_system.send_whisper(to, msg)
_append(1, T_WHISPER, "→ %s: %s" % [to, msg])
_append(0, T_WHISPER, "→ %s: %s" % [to, msg])
_close_whisper()
@@ -385,6 +414,8 @@ func _on_submit(text: String) -> void:
var to := rest.substr(0, sp)
var msg := rest.substr(sp + 1).strip_edges()
client.whisper(to, msg)
if _whisper_system:
_whisper_system.send_whisper(to, msg)
_append(1, T_WHISPER, "→ %s: %s" % [to, msg])
return
var map := {"/g ": T_GUILD, "/p ": T_PARTY, "/s ": T_SHOUT}
@@ -412,12 +443,43 @@ func _on_chat(type: int, vid: int, text: String) -> void:
func _on_whisper(sub: int, from: String, text: String) -> void:
var tag := from
if sub == 1:
tag = "[系统]"
elif sub == 2:
var line := text
if sub == WHISPER_TYPE_GM:
tag = "[GM] " + from
_append(1, T_WHISPER, "%s: %s" % [tag, text])
_append(0, T_WHISPER, "%s: %s" % [tag, text])
if _whisper_system:
var gm_result: Dictionary = _whisper_system.receive_whisper(from, text, true)
if not bool(gm_result.get("delivered", false)):
return
elif sub == WHISPER_TYPE_SYSTEM:
tag = "[系统]"
elif sub == WHISPER_TYPE_CHAT:
if _whisper_system:
var chat_result: Dictionary = _whisper_system.receive_whisper(from, text)
if not bool(chat_result.get("delivered", false)):
return
elif sub != WHISPER_TYPE_CHAT:
# game.py::OnRecvWhisperError converts modes 1..4 through
# localeInfo.WHISPER_ERROR and appends them as a system whisper. The
# native signal carries the wire text as a best-effort fallback; use a
# stable localized fallback when the server sends an empty error body.
tag = "[系统]"
if line == "":
line = _whisper_error_text(sub, from)
_append(1, T_WHISPER, "%s: %s" % [tag, line])
_append(0, T_WHISPER, "%s: %s" % [tag, line])
func _whisper_error_text(sub: int, from: String) -> String:
match sub:
WHISPER_TYPE_NOT_EXIST:
return _loc("WHISPER_NOT_EXIST", "无法私聊:%s 不在线。", [from])
WHISPER_TYPE_TARGET_BLOCKED:
return _loc("WHISPER_TARGET_BLOCKED", "无法私聊:%s 拒绝了私聊。", [from])
WHISPER_TYPE_SENDER_BLOCKED:
return _loc("WHISPER_SENDER_BLOCKED", "无法私聊:%s 屏蔽了你。", [from])
WHISPER_TYPE_ERROR:
return _loc("WHISPER_ERROR", "私聊失败。")
_:
return _loc("WHISPER_UNKNOWN_ERROR", "未知私聊错误(模式 %d,目标 %s)。", [sub, from])
func _on_pickup(vnum: int, count: int, from: String) -> void:
var s := "拾取 #%d x%d" % [vnum, count]