# ExchangeUI (P8) —— 交易 / 换货窗。 # # var xu := preload("res://ui/exchange_ui.gd").new() # add_child(xu) # xu.setup(m2client, canvas_parent, proto) # proto 可空 # # 两栏:我方 / 对方,各列道具行 + 金币。底部:金币输入 + [放金币]、[接受]、[取消]。 # `exchange_changed` 刷新(active=false 时自动关闭)。 # inventory_ui 在交易开着时右键道具 → 调 xu.offer(win, cell)。 extends Node var client: Node var proto: Node var _root: Control var _self_box: VBoxContainer var _peer_box: VBoxContainer var _self_gold: Label var _peer_gold: Label var _status: Label var _accept_btn: Button var _gold_input: LineEdit var _next_display := 0 var _offered_cells := {} func setup(m2client: Node, parent: Node, proto_node: Node = null) -> void: client = m2client proto = proto_node _build(parent) if client.has_signal("exchange_changed"): client.exchange_changed.connect(refresh) func is_open() -> bool: return _root != null and _root.visible func offer(inv_window: int, inv_cell: int) -> void: if not is_open() or inv_window < 0 or inv_cell < 0: return var key := "%d:%d" % [inv_window, inv_cell] if _offered_cells.has(key): _status.text = "该物品已经放入交易" return var x: Dictionary = client.get_exchange() var used := {} for item in x.get("self_items", []): used[int(item.get("slot", -1))] = true for i in 12: if not used.has(i): _next_display = i break if used.size() >= 12: _status.text = "交易物品栏已满" return if client.exchange_add_item(inv_window, inv_cell, _next_display): _offered_cells[key] = true _next_display = (_next_display + 1) % 12 _status.text = "" else: _status.text = "交易请求发送失败" func _name_of(vnum: int) -> String: if proto and proto.has_method("item"): var d: Dictionary = proto.item(vnum) var n := String(d.get("locale_name", d.get("name", ""))) if n != "": return n return "#%d" % vnum func refresh() -> void: if client == null: return var x: Dictionary = client.get_exchange() if not x.get("active", false): _root.visible = false _next_display = 0 _offered_cells.clear() _gold_input.text = "" _status.text = "" return _root.visible = true _fill(_self_box, x.get("self_items", [])) _fill(_peer_box, x.get("peer_items", [])) _self_gold.text = "金币: %d" % int(x.get("self_gold", 0)) _peer_gold.text = "金币: %d" % int(x.get("peer_gold", 0)) var me: bool = x.get("self_accept", false) var peer: bool = x.get("peer_accept", false) _accept_btn.text = "已接受 ✓" if me else "接受" _accept_btn.modulate = Color(0.5, 1, 0.5) if me else Color(1, 1, 1) _root.get_node("PeerAccept").text = "对方: 已接受" if peer else "对方: 未接受" _status.text = "" func _fill(box: VBoxContainer, rows: Array) -> void: for c in box.get_children(): c.queue_free() for r in rows: var l := Label.new() l.text = "%s ×%d" % [_name_of(int(r.get("vnum", 0))), int(r.get("count", 1))] l.add_theme_font_size_override("font_size", 12) box.add_child(l) func _on_put_gold() -> void: var raw := _gold_input.text.strip_edges() if raw == "" or not raw.is_valid_int(): _status.text = "请输入有效金币数量" return var g := int(raw) if g <= 0 or g > 2000000000: _status.text = "金币数量必须在 1~2000000000 之间" return if client.exchange_add_gold(g): _gold_input.text = "" _status.text = "" else: _status.text = "金币请求发送失败" func _build(parent: Node) -> void: _root = Control.new() _root.set_anchors_preset(Control.PRESET_CENTER) _root.position = Vector2(-220, -180) _root.size = Vector2(440, 360) _root.visible = false _root.set_meta("is_titlebar", true) parent.add_child(_root) var panel := Panel.new() panel.set_anchors_preset(Control.PRESET_FULL_RECT) var sb := StyleBoxFlat.new() sb.bg_color = Color(0.07, 0.08, 0.1, 0.97) sb.set_corner_radius_all(4) panel.add_theme_stylebox_override("panel", sb) _root.add_child(panel) var title := Label.new() title.text = "交易" title.position = Vector2(12, 8) _root.add_child(title) var sl := Label.new() sl.text = "我方" sl.position = Vector2(20, 34) _root.add_child(sl) _self_box = VBoxContainer.new() _self_box.position = Vector2(20, 56) _self_box.custom_minimum_size = Vector2(200, 0) _root.add_child(_self_box) _self_gold = Label.new() _self_gold.text = "金币: 0" _self_gold.position = Vector2(20, 250) _root.add_child(_self_gold) var pl := Label.new() pl.text = "对方" pl.position = Vector2(240, 34) _root.add_child(pl) _peer_box = VBoxContainer.new() _peer_box.position = Vector2(240, 56) _peer_box.custom_minimum_size = Vector2(180, 0) _root.add_child(_peer_box) _peer_gold = Label.new() _peer_gold.text = "金币: 0" _peer_gold.position = Vector2(240, 250) _root.add_child(_peer_gold) _status = Label.new() _status.position = Vector2(20, 276) _status.add_theme_font_size_override("font_size", 11) _status.add_theme_color_override("font_color", Color(1, 0.65, 0.55)) _root.add_child(_status) var pa := Label.new() pa.name = "PeerAccept" pa.text = "对方: 未接受" pa.position = Vector2(240, 272) pa.add_theme_font_size_override("font_size", 12) _root.add_child(pa) var bottom := HBoxContainer.new() bottom.position = Vector2(20, 310) _root.add_child(bottom) _gold_input = LineEdit.new() _gold_input.placeholder_text = "金币" _gold_input.custom_minimum_size = Vector2(90, 0) bottom.add_child(_gold_input) var put := Button.new() put.text = "放金币" put.pressed.connect(_on_put_gold) bottom.add_child(put) _accept_btn = Button.new() _accept_btn.text = "接受" _accept_btn.pressed.connect(func() -> void: client.exchange_accept()) bottom.add_child(_accept_btn) var cancel := Button.new() cancel.text = "取消" cancel.pressed.connect(func() -> void: client.exchange_cancel()) bottom.add_child(cancel)