- 桥梁与静态物体高度采样修复: - 严格对齐 40250 CMapOutdoor::GetHeight 与 CAttributeInstance::GetHeight - 解析 .mdatr 中的 AttributeHeight 网格,使用 is_in_triangle_2d 准确计算桥面多边形平面方程 - sample_height 查询邻近区块并返回 fMAX(fObjectHeight, fTerrainHeight),彻底解决走上桥面穿透掉入水底/河床的问题 - 新增 test_bridge_height_parity.gd 自动化对拍测试 - 40250 怪物击杀经验动效: - 1:1 实现 FLY_EXP(0) / FLY_HP / FLY_SP 粒子轨迹与爆炸吸附 - 40250 客户端全系统功能对齐(Batches 1-31): - 包含公会、交易、骑乘、变身、钓鱼、采矿、商城、信件、结婚、地牢等 134 套对拍系统与自动化回归测试 - 文档沉淀: - 新增 docs/CLIENT-PARITY-AUDIT-AND-FIX-GUIDE.md 客户端对拍缺陷发现与修复工程指南
132 lines
4.0 KiB
GDScript
132 lines
4.0 KiB
GDScript
# 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)
|
|
|
|
const DEFAULT_ITEM_SALE_UNIT_PRICE := 100 # 默认单件基础回收金币
|
|
|
|
# 堆叠精准拆分 (Shift + 左键)
|
|
func split_item(
|
|
source_slot: int,
|
|
split_count: int,
|
|
target_slot: int,
|
|
inventory: Array
|
|
) -> 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": "目标栏位已被占用!"}
|
|
|
|
# 执行拆分
|
|
source_item["count"] = current_count - split_count
|
|
|
|
var new_stack = source_item.duplicate(true)
|
|
new_stack["count"] = split_count
|
|
inventory[dest_slot] = new_stack
|
|
|
|
item_split.emit(source_slot, dest_slot, split_count)
|
|
|
|
return {
|
|
"ok": true,
|
|
"source_slot": source_slot,
|
|
"target_slot": dest_slot,
|
|
"remaining_source": source_item["count"],
|
|
"split_count": split_count,
|
|
"msg": "成功拆分出 %d 件物品!" % split_count
|
|
}
|
|
|
|
# 快捷批量出售给商人 (Ctrl + 右键)
|
|
func quick_sell_item(
|
|
slot_idx: int,
|
|
inventory: Array,
|
|
player_data: Dictionary
|
|
) -> 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": "已加锁的物品严禁出售!"}
|
|
|
|
var count: int = int(item.get("count", 1))
|
|
var unit_price: int = int(item.get("sale_price", DEFAULT_ITEM_SALE_UNIT_PRICE))
|
|
var total_gold := unit_price * count
|
|
|
|
# 增加金币并清空格子
|
|
player_data["gold"] = int(player_data.get("gold", 0)) + total_gold
|
|
var iname: String = item.get("name", "物品")
|
|
inventory[slot_idx] = null
|
|
|
|
item_quick_sold.emit(slot_idx, total_gold, iname)
|
|
|
|
return {
|
|
"ok": true,
|
|
"slot_idx": slot_idx,
|
|
"gold_received": total_gold,
|
|
"item_name": iname,
|
|
"msg": "已快捷出售【%s x%d】,获得 %d 金币!" % [iname, count, total_gold]
|
|
}
|
|
|
|
# 高价值物品丢弃/销毁防误触检查
|
|
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
|
|
}
|