# jewelry_socket_system.gd —— Metin2 40250 首饰饰品金刚石打孔与精炼宝石镶嵌 1:1 # 对照 40250 服务端 char_item.cpp (PutGemInAccessory), item_attribute.cpp class_name JewelrySocketSystem extends RefCounted const ITEM_DIAMOND := 50621 # 精炼金刚石 const MAX_SOCKETS := 3 const GEM_LIFETIME_SECS := 86400.0 # 24 小时战斗佩戴寿命 # 饰品支持打孔的分类 (14:手镯, 16:项链, 17:耳环) const VALID_ACCESSORY_PREFIXES := [14, 16, 17] # 饰品材质与对应精炼宝石映射 (base_vnum_pattern -> gem_vnum) const ACCESSORY_GEM_MAPPING: Dictionary = { "copper": 50624, # 铜首饰 -> 铜 50624 "silver": 50625, # 银首饰 -> 银 50625 "gold": 50626, # 金首饰 -> 金 50626 "jade": 50627, # 玉首饰 -> 玉 50627 "ebony": 50628, # 黑檀首饰 -> 黑檀 50628 "pearl": 50629, # 珍珠首饰 -> 珍珠 50629 "white_gold": 50630, # 白金首饰 -> 白金 50630 "crystal": 50631, # 水晶首饰 -> 水晶 50631 "amethyst": 50632, # 紫晶首饰 -> 紫晶 50632 "heavens_tear": 50633,# 天泪首饰 -> 天泪石 50633 "soul_crystal": 50634,# 灵魂水晶首饰 -> 灵魂水晶 50634 "ruby": 50635, # 红宝石首饰 -> 红宝石 50635 "garnet": 50636, # 石榴石首饰 -> 石榴石 50636 "emerald": 50637, # 绿宝石首饰 -> 绿宝石 50637 "sapphire": 50638 # 蓝宝石首饰 -> 蓝宝石 50638 } # 打孔成功率 (0孔打第1孔: 70%, 1孔打第2孔: 50%, 2孔打第3孔: 30%) const DRILL_CHANCES: Array[float] = [0.70, 0.50, 0.30] # 宝石阶梯增益百分比 (第1孔: +10%, 第2孔: +10%, 第3孔: +20%) const GEM_BONUS_TIERS: Array[float] = [0.10, 0.10, 0.20] static func is_accessory(item: Dictionary) -> bool: var vnum: int = int(item.get("vnum", 0)) var prefix: int = int(floor(float(vnum) / 1000.0)) return prefix in VALID_ACCESSORY_PREFIXES # 检查是否可用金刚石打孔 static func can_drill_socket(item: Dictionary) -> Dictionary: if not is_accessory(item): return {"ok": false, "reason": "NOT_ACCESSORY", "msg": "金刚石只能用于手镯、项链或耳环打孔!"} var socket_count: int = int(item.get("socket_count", 0)) if socket_count >= MAX_SOCKETS: return {"ok": false, "reason": "SOCKETS_FULL", "msg": "该首饰已拥有最大的 3 个宝石孔槽!"} return {"ok": true, "current_sockets": socket_count} # 使用金刚石 50621 打孔 static func drill_socket(item: Dictionary, diamond_slot_item: Dictionary, force_success: bool = false) -> Dictionary: var check = can_drill_socket(item) if not check["ok"]: return check var dvnum: int = int(diamond_slot_item.get("vnum", 0)) if dvnum != ITEM_DIAMOND: return {"ok": false, "reason": "NOT_DIAMOND", "msg": "打孔必须使用精炼金刚石!"} var current_sockets: int = int(item.get("socket_count", 0)) var chance: float = DRILL_CHANCES[current_sockets] var roll: float = 0.0 if force_success else randf() var success: bool = roll < chance if not item.has("sockets"): item["sockets"] = [0, 0, 0] if not item.has("gem_times"): item["gem_times"] = [0.0, 0.0, 0.0] if success: item["socket_count"] = current_sockets + 1 return { "ok": true, "success": true, "socket_count": item["socket_count"], "msg": "打孔成功!已开辟出第 %d 个宝石孔槽!" % item["socket_count"] } else: return { "ok": true, "success": false, "socket_count": current_sockets, "msg": "打孔失败!金刚石破碎,未能开出孔槽。" } # 镶嵌精炼矿石宝石 static func insert_gem(item: Dictionary, gem_item: Dictionary, required_gem_vnum: int = 0) -> Dictionary: if not is_accessory(item): return {"ok": false, "reason": "NOT_ACCESSORY"} var socket_count: int = int(item.get("socket_count", 0)) if socket_count <= 0: return {"ok": false, "reason": "NO_SOCKETS_DRILLED", "msg": "该首饰尚未打孔,请先使用金刚石开孔!"} if not item.has("sockets"): item["sockets"] = [0, 0, 0] if not item.has("gem_times"): item["gem_times"] = [0.0, 0.0, 0.0] # 查找第一个空孔 var empty_slot := -1 for i in range(socket_count): if int(item["sockets"][i]) == 0: empty_slot = i break if empty_slot == -1: return {"ok": false, "reason": "NO_EMPTY_SOCKET", "msg": "所有已开辟的孔槽都已镶嵌满宝石!"} var gem_vnum: int = int(gem_item.get("vnum", 0)) if gem_vnum < 50622 or gem_vnum > 50638: return {"ok": false, "reason": "INVALID_GEM", "msg": "这不是有效的精炼宝石!"} if required_gem_vnum > 0 and gem_vnum != required_gem_vnum: return {"ok": false, "reason": "GEM_MISMATCH", "msg": "此宝石与该首饰材质不匹配!"} # 镶嵌成功 item["sockets"][empty_slot] = gem_vnum item["gem_times"][empty_slot] = GEM_LIFETIME_SECS var active_gems := count_active_gems(item) var bonus_pct := calculate_bonus_percentage(active_gems) return { "ok": true, "slot": empty_slot, "gem_vnum": gem_vnum, "active_gems": active_gems, "total_bonus_pct": bonus_pct, "lifetime": GEM_LIFETIME_SECS, "msg": "宝石成功镶入第 %d 个孔槽!固有属性提升 %d%%!" % [empty_slot + 1, int(round(bonus_pct * 100))] } # 统计当前生效的宝石数量 static func count_active_gems(item: Dictionary) -> int: var count := 0 var sockets: Array = item.get("sockets", []) var times: Array = item.get("gem_times", []) for i in range(sockets.size()): if int(sockets[i]) > 0 and float(times[i]) > 0.0: count += 1 return count # 计算宝石提供的总属性加成百分比 (0~3 颗宝石) static func calculate_bonus_percentage(gem_count: int) -> float: var pct: float = 0.0 for i in range(mini(gem_count, GEM_BONUS_TIERS.size())): pct += GEM_BONUS_TIERS[i] return pct # 佩戴战斗时间自然衰减 (dt: 秒) static func update_gem_endurance(item: Dictionary, dt: float) -> Dictionary: var expired_gems: Array[int] = [] if not item.has("sockets") or not item.has("gem_times"): return {"expired": expired_gems} var sockets: Array = item["sockets"] var times: Array = item["gem_times"] for i in range(sockets.size()): if int(sockets[i]) > 0 and float(times[i]) > 0.0: times[i] = maxf(0.0, float(times[i]) - dt) if float(times[i]) <= 0.0: expired_gems.append(int(sockets[i])) sockets[i] = 0 # 宝石破碎,孔槽重新清空 return { "expired": expired_gems, "active_gems": count_active_gems(item), "total_bonus_pct": calculate_bonus_percentage(count_active_gems(item)) }