Files
mtgodot-poc/project/mining_refinery_smelt_system.gd
T
shenandshen 66d217b313 feat(client): 完成40250客户端核心功能1:1对齐与桥梁高度采样修复
- 桥梁与静态物体高度采样修复:
  - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
2026-09-19 08:51:25 -07:00

193 lines
7.1 KiB
GDScript

# mining_refinery_smelt_system.gd —— Metin2 40250 矿石采掘熔炼与首饰宝石镶嵌提纯炉系统 1:1
# 对照 40250 服务端 mining.cpp, char_item.cpp, item_manager.cpp
class_name MiningRefinerySmeltSystem
extends RefCounted
signal ore_smelted(success: bool, gem_vnum: int, gem_name: String)
signal jewelry_socket_opened(slot: int, socket_index: int)
signal gem_embedded(slot: int, gem_name: String, stat_boost: float)
const SMELT_ORE_COUNT := 100 # 熔炼需 100 颗原石
const SMELT_COST_GOLD := 10000 # 熔炼消耗 10,000 金币
const MAX_JEWELRY_SOCKETS := 3 # 首饰最多开 3 个孔
# 原石与精炼宝石对照表
const SMELT_TABLE: Dictionary = {
50621: {"name": "钻石原石", "gem_vnum": 50634, "gem_name": "纯净钻石", "is_diamond": true},
50623: {"name": "乌木原石", "gem_vnum": 50636, "gem_name": "乌木精炼石", "is_diamond": false},
50626: {"name": "黄金原石", "gem_vnum": 50639, "gem_name": "黄金精炼石", "is_diamond": false},
50628: {"name": "白金原石", "gem_vnum": 50641, "gem_name": "白金精炼石", "is_diamond": false},
50630: {"name": "天之泪原石", "gem_vnum": 50643, "gem_name": "天之泪精炼石", "is_diamond": false}
}
# 熔炼原石生成首饰宝石
func smelt_ore(ore_slot: int, stone_slot: int, inventory: Array, player_data: Dictionary, is_guild_alchemist: bool = false, force_success: bool = false) -> Dictionary:
if ore_slot < 0 or ore_slot >= inventory.size() or inventory[ore_slot] == null:
return {"ok": false, "reason": "INVALID_ORE_SLOT"}
if stone_slot < 0 or stone_slot >= inventory.size() or inventory[stone_slot] == null:
return {"ok": false, "reason": "INVALID_STONE_SLOT"}
var ore_item = inventory[ore_slot]
var stone_item = inventory[stone_slot]
var ore_vnum = int(ore_item.get("vnum", 0))
if not SMELT_TABLE.has(ore_vnum):
return {"ok": false, "reason": "NOT_AN_ORE", "msg": "该物品不是可熔炼的原矿石!"}
var ore_count = int(ore_item.get("count", 1))
if ore_count < SMELT_ORE_COUNT:
return {"ok": false, "reason": "NOT_ENOUGH_ORE", "msg": "原矿数量不足!需要 100 颗,当前仅有 %d 颗。" % ore_count}
var gold = int(player_data.get("gold", 0))
if gold < SMELT_COST_GOLD:
return {"ok": false, "reason": "NOT_ENOUGH_GOLD", "msg": "熔炼所需金币不足!需要 10,000 金币。"}
# 消耗材料与金币
player_data["gold"] = gold - SMELT_COST_GOLD
if ore_count > SMELT_ORE_COUNT:
ore_item["count"] = ore_count - SMELT_ORE_COUNT
else:
inventory[ore_slot] = null
var stone_cnt = int(stone_item.get("count", 1))
if stone_cnt > 1:
stone_item["count"] = stone_cnt - 1
else:
inventory[stone_slot] = null
# 成功率计算 (普通提纯炉 60%,公会炼金炉 70%)
var rate = 70 if is_guild_alchemist else 60
var roll = randi_range(1, 100)
var is_succ = force_success or (roll <= rate)
var target_gem = SMELT_TABLE[ore_vnum]
var gem_vnum = target_gem["gem_vnum"]
var gem_name = target_gem["gem_name"]
if is_succ:
# 入包精炼宝石
_add_gem_to_inventory(gem_vnum, gem_name, inventory)
ore_smelted.emit(true, gem_vnum, gem_name)
return {
"ok": true,
"success": true,
"gem_vnum": gem_vnum,
"gem_name": gem_name,
"msg": "提纯炉烈焰喷涌!成功熔炼出高纯度【%s】!" % gem_name
}
else:
ore_smelted.emit(false, gem_vnum, gem_name)
return {
"ok": true,
"success": false,
"msg": "熔炼失败!火候不纯,矿石与灵石化为了灰烬。"
}
# 使用纯净钻石 (50634) 为首饰打孔
func open_jewelry_socket(diamond_slot: int, target_slot: int, inventory: Array, force_success: bool = false) -> Dictionary:
if diamond_slot < 0 or diamond_slot >= inventory.size() or inventory[diamond_slot] == null:
return {"ok": false, "reason": "INVALID_DIAMOND_SLOT"}
if target_slot < 0 or target_slot >= inventory.size() or inventory[target_slot] == null:
return {"ok": false, "reason": "INVALID_TARGET_SLOT"}
var d_item = inventory[diamond_slot]
var target = inventory[target_slot]
if int(d_item.get("vnum", 0)) != 50634:
return {"ok": false, "reason": "NOT_A_DIAMOND", "msg": "打孔需要使用【纯净钻石】(50634)!"}
if not target.has("jewelry_sockets"):
target["jewelry_sockets"] = []
var sockets: Array = target["jewelry_sockets"]
if sockets.size() >= MAX_JEWELRY_SOCKETS:
return {"ok": false, "reason": "MAX_SOCKETS_REACHED", "msg": "该首饰已开辟 3 个宝石孔位,达到上限!"}
# 消耗 1 颗钻石
var cnt = int(d_item.get("count", 1))
if cnt > 1:
d_item["count"] = cnt - 1
else:
inventory[diamond_slot] = null
# 阶梯成功率: 第 1 孔 100%,第 2 孔 80%,第 3 孔 60%
var rates = [100, 80, 60]
var rate = rates[sockets.size()]
var roll = randi_range(1, 100)
var is_succ = force_success or (roll <= rate)
if not is_succ:
return {"ok": true, "success": false, "msg": "打孔失败!钻石碎裂,未能开辟新孔位。"}
sockets.append(null) # 开辟一个空孔位
jewelry_socket_opened.emit(target_slot, sockets.size())
return {
"ok": true,
"success": true,
"socket_index": sockets.size(),
"total_sockets": sockets.size(),
"msg": "打孔成功!首饰开辟了第 %d 个宝石镶嵌孔位!" % sockets.size()
}
# 将精炼宝石镶入首饰已开孔位
func embed_gem_into_socket(gem_slot: int, target_slot: int, inventory: Array) -> Dictionary:
if gem_slot < 0 or gem_slot >= inventory.size() or inventory[gem_slot] == null:
return {"ok": false, "reason": "INVALID_GEM_SLOT"}
if target_slot < 0 or target_slot >= inventory.size() or inventory[target_slot] == null:
return {"ok": false, "reason": "INVALID_TARGET_SLOT"}
var gem_item = inventory[gem_slot]
var target = inventory[target_slot]
if not target.has("jewelry_sockets") or target["jewelry_sockets"].is_empty():
return {"ok": false, "reason": "NO_SOCKETS", "msg": "该首饰尚未开孔!请先使用纯净钻石打孔。"}
var sockets: Array = target["jewelry_sockets"]
var empty_idx = -1
for i in range(sockets.size()):
if sockets[i] == null:
empty_idx = i
break
if empty_idx == -1:
return {"ok": false, "reason": "ALL_SOCKETS_OCCUPIED", "msg": "所有宝石孔位已镶满!"}
var gem_vnum = int(gem_item.get("vnum", 0))
var gem_name = gem_item.get("name", "宝石")
# 消耗 1 颗宝石
var cnt = int(gem_item.get("count", 1))
if cnt > 1:
gem_item["count"] = cnt - 1
else:
inventory[gem_slot] = null
# 镶入孔位 (每颗宝石提供 +10% 首饰属性增强)
sockets[empty_idx] = {
"vnum": gem_vnum,
"name": gem_name,
"stat_boost": 0.10
}
gem_embedded.emit(target_slot, gem_name, 0.10)
return {
"ok": true,
"socket_idx": empty_idx,
"gem_name": gem_name,
"stat_boost": 0.10,
"msg": "【%s】完美嵌入第 %d 孔!激活 +10%% 首饰属性加成!" % [gem_name, empty_idx + 1]
}
func _add_gem_to_inventory(vnum: int, iname: String, inventory: Array) -> void:
for i in range(inventory.size()):
if inventory[i] != null and int(inventory[i].get("vnum", 0)) == vnum:
inventory[i]["count"] = int(inventory[i].get("count", 1)) + 1
return
for i in range(inventory.size()):
if inventory[i] == null:
inventory[i] = {"vnum": vnum, "name": iname, "count": 1}
return