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
+61 -4
View File
@@ -56,6 +56,7 @@ const WINDOW_INVENTORY := 1 # mtnet::WINDOW_INVENTORY
const WINDOW_EQUIPMENT := 2 # mtnet::WINDOW_EQUIPMENT(旧 11 格 wear)
const WINDOW_SAFEBOX := 3 # global mouse payload source, not an inventory window
const WINDOW_MALL := 4 # global mouse payload source, not an inventory window
const WINDOW_BELT := 7 # m2dev belt-inventory window
const BELT_RULES := [1, 2, 4, 6, 3, 3, 4, 6, 5, 5, 5, 6, 7, 7, 7, 7]
var ui: CanvasLayer # UiManager
@@ -99,8 +100,14 @@ func setup(ui_manager: CanvasLayer, m2client: Node, proto_node: Node, assets: St
uiscript_dir = assets.path_join("uiscript/uiscript")
if not DirAccess.dir_exists_absolute(uiscript_dir):
uiscript_dir = assets.path_join("uiscript")
if client and client.has_signal("inventory_changed"):
if client and client.has_signal("inventory_state_changed"):
# 40250 refreshes once after SetItemCount and once after sockets/attrs;
# consume the state snapshots so the first refresh sees the old sockets.
client.inventory_state_changed.connect(_on_inventory_state_changed)
elif client and client.has_signal("inventory_changed"):
client.inventory_changed.connect(_on_inv_changed)
if client and client.has_signal("item_highlighted"):
client.item_highlighted.connect(_on_item_highlighted)
if ui and ui.has_signal("window_closed"):
ui.window_closed.connect(func(w):
if not _win.is_empty() and _win.get("root") == w:
@@ -193,6 +200,35 @@ func refresh() -> void:
func _on_inv_changed(_window: int, _cell: int) -> void:
refresh()
func _on_inventory_state_changed(window: int, cell: int, item: Dictionary) -> void:
if not is_open():
return
var ui_idx := _wire_to_ui(window, cell)
var slot: Panel = _cells.get(ui_idx, null)
if slot == null:
return
var vnum := int(item.get("vnum", 0))
if vnum <= 0:
_clear_cell(slot)
else:
_fill_cell(slot, vnum, int(item.get("count", 1)), item)
if window == WINDOW_EQUIPMENT and client.has_method("get_equipment"):
_apply_belt_locks(client.get_equipment())
func _on_item_highlighted(window: int, cell: int) -> void:
if not is_open():
return
var ui_idx := _wire_to_ui(window, cell)
var slot: Panel = _cells.get(ui_idx, null)
if slot == null or int(slot.get_meta("vnum", 0)) <= 0:
return
slot.set_meta("highlighted", true)
slot.modulate = Color.WHITE
var pulse := create_tween()
pulse.set_loops(2)
pulse.tween_property(slot, "modulate", Color(1.0, 0.82, 0.28, 1.0), 0.12)
pulse.tween_property(slot, "modulate", Color.WHITE, 0.12)
func _fill_cell(cell: Panel, vnum: int, count: int, instance_data: Dictionary = {}) -> void:
_clear_cell(cell)
cell.set_meta("vnum", vnum)
@@ -204,10 +240,15 @@ func _fill_cell(cell: Panel, vnum: int, count: int, instance_data: Dictionary =
proto_data = proto.item(vnum)
if not proto_data.is_empty():
name = String(proto_data.get("locale_name", proto_data.get("name", name)))
var tooltip_body := ""
if item_tooltip:
cell.tooltip_text = item_tooltip.format(vnum, count, proto_data, instance_data)
tooltip_body = item_tooltip.format(vnum, count, proto_data, instance_data)
else:
cell.tooltip_text = "%s\n#%d%s" % [name, vnum, (" x%d" % count) if count > 1 else ""]
tooltip_body = "%s\n#%d%s" % [name, vnum, (" x%d" % count) if count > 1 else ""]
# 40250 has one custom item-attribute panel owner. Do not also let Godot
# create its native tooltip popup; the mobile detail dialog reads this body.
cell.set_meta("tooltip_body", tooltip_body)
cell.tooltip_text = ""
var tex := _icon(vnum)
if tex:
var tr := TextureRect.new()
@@ -238,6 +279,9 @@ func _clear_cell(cell: Panel) -> void:
cell.set_meta("vnum", 0)
cell.set_meta("count", 0)
cell.set_meta("item_data", {})
cell.set_meta("tooltip_body", "")
cell.set_meta("highlighted", false)
cell.modulate = Color.WHITE
cell.tooltip_text = ""
for c in cell.get_children():
c.queue_free()
@@ -618,7 +662,8 @@ func _show_mobile_detail(ui_idx: int) -> void:
title.add_theme_color_override("font_color", Color(0.98, 0.84, 0.52))
dialog.add_child(title)
var detail := Label.new()
detail.text = "物品编号:%d\n数量:%d\n\n%s" % [vnum, count, String(cell.tooltip_text)]
detail.text = "物品编号:%d\n数量:%d\n\n%s" % [vnum, count,
String(cell.get_meta("tooltip_body", ""))]
detail.position = Vector2(18, 84)
detail.size = Vector2(324, 70)
detail.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
@@ -955,3 +1000,15 @@ func _to_wire(ui_idx: int) -> Array:
# 旧 11 格(BODY..SHIELD)走 EQUIPMENT 窗(window=2)+ 零基 wear cell。
return [WINDOW_EQUIPMENT, wear]
return [WINDOW_INVENTORY, ui_idx]
# wire item position -> the same UI slot namespace used by _to_wire().
func _wire_to_ui(window: int, cell: int) -> int:
if window == WINDOW_EQUIPMENT:
return EQUIP_BASE + (cell - EQUIP_BASE if cell >= EQUIP_BASE else cell)
if window == WINDOW_BELT:
return BELT_BASE + (cell - BELT_SLOT_START if cell >= BELT_SLOT_START else cell)
if window == WINDOW_INVENTORY:
if cell >= BELT_SLOT_START:
return BELT_BASE + cell - BELT_SLOT_START
return cell
return -1