# item_split_system.gd —— Metin2 40250 物品堆叠精准拆分与快捷批量操作 1:1 # 对照 40250 服务端 char_item.cpp, input_main.cpp, uiinventory.py class_name ItemSplitSystem extends RefCounted signal item_split(source_slot: int, target_slot: int, split_count: int) signal item_quick_sold(slot_idx: int, gold_received: int, item_name: String) signal item_split_requested(source_slot: int, target_slot: int, split_count: int) signal item_quick_sell_requested(slot_idx: int, count: int, item_name: String) # 堆叠精准拆分 (Shift + 左键) func split_item( source_slot: int, split_count: int, target_slot: int, inventory: Array, client: Node = null, source_window: int = 1, target_window: int = 1 ) -> Dictionary: if source_slot < 0 or source_slot >= inventory.size(): return {"ok": false, "reason": "INVALID_SOURCE_SLOT", "msg": "无效的源栏位!"} var source_item = inventory[source_slot] if source_item == null: return {"ok": false, "reason": "EMPTY_SOURCE_SLOT", "msg": "源栏位上没有物品!"} var current_count: int = int(source_item.get("count", 1)) if current_count <= 1: return {"ok": false, "reason": "NOT_SPLITTABLE", "msg": "单件物品无法拆分!"} if split_count < 1 or split_count >= current_count: return { "ok": false, "reason": "INVALID_SPLIT_COUNT", "max_allowed": current_count - 1, "msg": "拆分数量必须在 1 到 %d 之间!" % (current_count - 1) } # 确定目标格子 var dest_slot := target_slot if dest_slot < 0: for i in range(inventory.size()): if inventory[i] == null: dest_slot = i break if dest_slot < 0 or dest_slot >= inventory.size(): return {"ok": false, "reason": "NO_DEST_SLOT", "msg": "背包没有可用空位放置拆分出的物品!"} if inventory[dest_slot] != null: return {"ok": false, "reason": "DEST_SLOT_NOT_EMPTY", "msg": "目标栏位已被占用!"} # 40250 does not edit CPythonPlayer's item array optimistically. Splitting # is an ordinary CG_ITEM_MOVE(source, destination, count); both resulting # counts arrive later through GC_ITEM_UPDATE/SET. Keep this helper from # becoming a second local authority when it is used by desktop or mobile UI. if client == null or not client.has_method("move_item"): return {"ok": false, "reason": "NETWORK_CLIENT_REQUIRED", "msg": "拆分需要连接服务器确认!"} if not client.move_item(source_window, source_slot, target_window, dest_slot, split_count): return {"ok": false, "reason": "SEND_FAILED", "msg": "拆分请求发送失败!"} item_split_requested.emit(source_slot, dest_slot, split_count) return { "ok": true, "pending": true, "source_slot": source_slot, "target_slot": dest_slot, "remaining_source": current_count - split_count, "split_count": split_count, "msg": "已发送拆分请求,等待服务器确认!" } # 快捷批量出售给商人 (Ctrl + 右键) func quick_sell_item( slot_idx: int, inventory: Array, player_data: Dictionary, client: Node = null, window: int = 1 ) -> Dictionary: if slot_idx < 0 or slot_idx >= inventory.size(): return {"ok": false, "reason": "INVALID_SLOT", "msg": "无效的栏位!"} var item = inventory[slot_idx] if item == null: return {"ok": false, "reason": "EMPTY_SLOT", "msg": "该格子上没有物品!"} # 加锁保护 if item.get("is_locked", false): return {"ok": false, "reason": "ITEM_LOCKED", "msg": "已加锁的物品严禁出售!"} if window != 1: return {"ok": false, "reason": "INVALID_SELL_WINDOW", "msg": "只能出售背包中的物品!"} var count: int = int(item.get("count", 1)) # 40250's SELL/SELL2 response supplies the authoritative price and the # subsequent item/gold updates. Do not use sale_price/player_data as a local # substitute for the server result. if client == null or not client.has_method("shop_sell"): return {"ok": false, "reason": "NETWORK_CLIENT_REQUIRED", "msg": "出售需要连接服务器确认!"} if not client.shop_sell(slot_idx, count): return {"ok": false, "reason": "SEND_FAILED", "msg": "出售请求发送失败!"} var iname: String = item.get("name", "物品") item_quick_sell_requested.emit(slot_idx, count, iname) return { "ok": true, "pending": true, "slot_idx": slot_idx, "count": count, "item_name": iname, "msg": "已发送出售请求,等待服务器确认!" } # 高价值物品丢弃/销毁防误触检查 func check_drop_safety(item: Dictionary) -> Dictionary: if item.is_empty(): return {"can_drop": false} if item.get("is_locked", false): return { "can_drop": false, "require_confirm": false, "reason": "ITEM_LOCKED", "msg": "已加锁的贵重物品无法丢弃!" } var refine_level: int = int(item.get("refine_level", 0)) var has_attrs: bool = item.has("attributes") and not item["attributes"].is_empty() if refine_level >= 7 or has_attrs: return { "can_drop": true, "require_confirm": true, "msg": "此装备强化等级较高或拥有附加属性,属于贵重装备!确定要丢弃吗?" } return { "can_drop": true, "require_confirm": false }