完善客户端功能并同步差距文档
This commit is contained in:
@@ -18,6 +18,8 @@
|
||||
# M2Client classic 分支按该语义发送。
|
||||
extends Node
|
||||
|
||||
const ItemTooltip = preload("res://ui/item_tooltip.gd")
|
||||
|
||||
class PrivateShopDragButton extends Button:
|
||||
var drag_entry: Dictionary = {}
|
||||
|
||||
@@ -32,10 +34,13 @@ class PrivateShopDragButton extends Button:
|
||||
|
||||
const PRIVATE_SHOP_ITEM_MAX := 39 # PRIVATE_SHOP_ITEM_MAX_NUM (TPacketCGMyShop::bCount 上限)
|
||||
const SIGN_MAX := 25 # NameLine input_limit
|
||||
const ITEM_ANTIFLAG_GIVE := 1 << 13
|
||||
const ITEM_ANTIFLAG_MYSHOP := 1 << 16
|
||||
|
||||
var client: Node
|
||||
var ui: CanvasLayer # UiManager
|
||||
var proto: Node
|
||||
var _tooltip_builder: RefCounted
|
||||
var assets_root := ""
|
||||
var uiscript_dir := ""
|
||||
|
||||
@@ -48,6 +53,8 @@ var _stock: Dictionary = {} # 格号:int -> {cell, vnum, count, price}
|
||||
var _picked = null # {cell, vnum, count} 等待落位
|
||||
var _price_dialog: Control = null
|
||||
var _server_prices: Dictionary = {} # vnum -> last price returned by MyShopPriceList
|
||||
var item_mouse: Node
|
||||
const INVENTORY_WINDOW := 1
|
||||
|
||||
func setup(m2client: Node, ui_manager: CanvasLayer, proto_node: Node = null, assets := "") -> void:
|
||||
client = m2client
|
||||
@@ -56,6 +63,8 @@ func setup(m2client: Node, ui_manager: CanvasLayer, proto_node: Node = null, ass
|
||||
assets_root = assets
|
||||
if assets_root == "" and ui and "assets_root" in ui:
|
||||
assets_root = ui.assets_root
|
||||
_tooltip_builder = ItemTooltip.new()
|
||||
_tooltip_builder.setup(assets_root if assets_root != "" else AssetRoot.path(), "en", proto)
|
||||
uiscript_dir = assets_root.path_join("uiscript/uiscript")
|
||||
if not DirAccess.dir_exists_absolute(uiscript_dir):
|
||||
uiscript_dir = assets_root.path_join("uiscript")
|
||||
@@ -77,6 +86,10 @@ func toggle() -> void:
|
||||
|
||||
func close() -> void:
|
||||
_dismiss_price_dialog()
|
||||
if item_mouse and item_mouse.has_method("unregister_owner"):
|
||||
item_mouse.unregister_owner(self)
|
||||
if item_mouse.has_method("is_attached") and item_mouse.is_attached():
|
||||
item_mouse.cancel()
|
||||
if is_open():
|
||||
ui.close(_win["root"])
|
||||
_win = {}
|
||||
@@ -124,6 +137,28 @@ func _index_cells(root: Node) -> void:
|
||||
n.set_drag_forwarding(Callable(self, "_no_drag_data"),
|
||||
Callable(self, "_can_drop_slot").bind(idx),
|
||||
Callable(self, "_drop_slot").bind(idx))
|
||||
if item_mouse and item_mouse.has_method("register_target"):
|
||||
item_mouse.register_target(n,
|
||||
func(payload: Dictionary): return _drop_mouse_item(payload, idx), self)
|
||||
|
||||
func _drop_mouse_item(payload: Dictionary, slot: int) -> bool:
|
||||
if payload.is_empty() or slot < 0 or slot >= 40 or _stock.has(slot):
|
||||
return false
|
||||
if int(payload.get("window", -1)) != INVENTORY_WINDOW:
|
||||
return false
|
||||
var cell := int(payload.get("cell", -1))
|
||||
var vnum := int(payload.get("vnum", 0))
|
||||
if cell < 0 or vnum <= 0:
|
||||
return false
|
||||
var entry := payload.duplicate(true)
|
||||
entry["cell"] = cell
|
||||
entry["vnum"] = vnum
|
||||
entry["count"] = maxi(1, int(payload.get("count", 1)))
|
||||
if not _can_stock(entry):
|
||||
return false
|
||||
_picked = entry
|
||||
_ask_price(slot)
|
||||
return true
|
||||
|
||||
# NameLine 在 uiscript 里是 text(Label)—— 盖一个 LineEdit 上去
|
||||
func _overlay_name_edit(root: Control) -> void:
|
||||
@@ -219,10 +254,17 @@ func _refresh_inv() -> void:
|
||||
var count := int(it.get("count", 1))
|
||||
var b := PrivateShopDragButton.new()
|
||||
b.text = "%s ×%d" % [_name_of(vnum), count]
|
||||
if _tooltip_builder:
|
||||
var pd: Dictionary = proto.item(vnum) if proto and proto.has_method("item") else {}
|
||||
b.tooltip_text = _tooltip_builder.format(vnum, count, pd, it)
|
||||
b.alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||||
b.custom_minimum_size = Vector2(196, 22)
|
||||
b.toggle_mode = true
|
||||
var entry := {"cell": cell, "vnum": vnum, "count": count}
|
||||
var entry: Dictionary = it.duplicate(true)
|
||||
entry["cell"] = cell
|
||||
entry["vnum"] = vnum
|
||||
entry["count"] = count
|
||||
entry["anti_flags"] = int(it.get("anti_flags", 0))
|
||||
b.drag_entry = entry
|
||||
b.pressed.connect(func() -> void: _pick(entry, b))
|
||||
if _picked != null and int(_picked["cell"]) == cell:
|
||||
@@ -256,7 +298,13 @@ func _refresh_grid() -> void:
|
||||
pr.add_theme_color_override("font_color", Color(0.95, 0.85, 0.5))
|
||||
pr.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
cell.add_child(pr)
|
||||
cell.tooltip_text = "%s ×%d\n%d 냥" % [_name_of(int(s["vnum"])), int(s["count"]), int(s["price"])]
|
||||
var tooltip_item := s.duplicate(true)
|
||||
tooltip_item["count"] = int(s["count"])
|
||||
if _tooltip_builder:
|
||||
var pd: Dictionary = proto.item(int(s["vnum"])) if proto and proto.has_method("item") else {}
|
||||
cell.tooltip_text = _tooltip_builder.format(int(s["vnum"]), int(s["count"]), pd, tooltip_item)
|
||||
else:
|
||||
cell.tooltip_text = "%s ×%d\n%d 냥" % [_name_of(int(s["vnum"])), int(s["count"]), int(s["price"])]
|
||||
cell.modulate = Color(1, 1, 1)
|
||||
else:
|
||||
cell.modulate = Color(0.72, 0.72, 0.82) if _picked != null else Color(1, 1, 1)
|
||||
@@ -264,6 +312,8 @@ func _refresh_grid() -> void:
|
||||
# --- 상호작용 --------------------------------------------------------
|
||||
|
||||
func _pick(entry: Dictionary, _btn: Button) -> void:
|
||||
if not _can_stock(entry):
|
||||
return
|
||||
if _picked != null and int(_picked["cell"]) == int(entry["cell"]):
|
||||
_picked = null
|
||||
else:
|
||||
@@ -281,9 +331,36 @@ func _drop_slot(_at_position: Vector2, data, slot: int) -> void:
|
||||
if not _can_drop_slot(Vector2.ZERO, data, slot):
|
||||
return
|
||||
var entry: Dictionary = data["private_shop_entry"] as Dictionary
|
||||
if not _can_stock(entry):
|
||||
return
|
||||
_picked = entry.duplicate(true)
|
||||
_ask_price(slot)
|
||||
|
||||
func _source_item(cell: int) -> Dictionary:
|
||||
if client == null:
|
||||
return {}
|
||||
if client.has_method("get_item"):
|
||||
var direct: Dictionary = client.get_item(INVENTORY_WINDOW, cell)
|
||||
if not direct.is_empty():
|
||||
return direct
|
||||
if client.has_method("get_inventory"):
|
||||
for item in client.get_inventory():
|
||||
if int(item.get("cell", -1)) == cell:
|
||||
return item
|
||||
return {}
|
||||
|
||||
func _can_stock(entry: Dictionary) -> bool:
|
||||
var item_data := _source_item(int(entry.get("cell", -1)))
|
||||
var vnum := int(entry.get("vnum", item_data.get("vnum", 0)))
|
||||
var proto_data: Dictionary = proto.item(vnum) if proto and proto.has_method("item") else {}
|
||||
var flags := int(entry.get("anti_flags", 0)) | int(item_data.get("anti_flags", 0)) \
|
||||
| int(proto_data.get("anti_flags", 0))
|
||||
if (flags & (ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_MYSHOP)) != 0:
|
||||
if is_instance_valid(_status):
|
||||
_status.text = "该物品不可摆摊"
|
||||
return false
|
||||
return true
|
||||
|
||||
func _on_slot_clicked(slot: int) -> void:
|
||||
if _stock.has(slot):
|
||||
_stock.erase(slot)
|
||||
@@ -343,6 +420,10 @@ func _place(slot: int, price: int) -> void:
|
||||
if slot < 0 or slot >= 40 or price <= 0 or price > 2000000000 or _picked == null:
|
||||
_dismiss_price_dialog()
|
||||
return
|
||||
if not _can_stock(_picked):
|
||||
_dismiss_price_dialog()
|
||||
_picked = null
|
||||
return
|
||||
_stock[slot] = {"cell": int(_picked["cell"]), "vnum": int(_picked["vnum"]),
|
||||
"count": int(_picked["count"]), "price": price}
|
||||
_picked = null
|
||||
|
||||
Reference in New Issue
Block a user