# item_enchant_system.gd —— Metin2 40250 装备词条重铸与精炼附魔洗炼系统 1:1 # 对照 40250 服务端 char_item.cpp, item_attribute.cpp, constants.cpp class_name ItemEnchantSystem extends RefCounted const ItemAttrSystem = preload("res://item_attr_system.gd") signal enchant_applied(target_slot: int, scroll_vnum: int, success: bool, new_attrs: Array) signal rare_enchant_applied(target_slot: int, success: bool, rare_attrs: Array) signal enchant_failed(target_slot: int, reason: String) const VNUM_ATTR_ADD := 71085 # 添加属性秘籍 (添加第 1~4 条) const VNUM_ATTR_CHANGE := 71084 # 属性改变秘籍 (洗炼现有 1~5 条) const VNUM_BLESSING_MARBLE := 70024 # 祝福宝珠 (添加第 5 条属性) const VNUM_RARE_ADD := 71151 # 稀有属性秘籍 (添加第 6~7 条稀有词条) const VNUM_RARE_CHANGE := 71152 # 稀有属性改变 (单独洗炼第 6~7 条稀有词条) const ADD_PERCENT_TABLE := [100, 80, 60, 50, 30] # 官方各阶段成功率 const RARE_ADD_PERCENT := 50 # 稀有词条附加成功率 # 稀有词条池 (6~7 槽位特有词条) const RARE_ATTR_POOL := { 101: {"name": "全技能伤害加成", "values": [1, 2, 3, 5, 8], "weight": 8}, 102: {"name": "首领怪物伤害加成", "values": [2, 4, 6, 8, 12], "weight": 8}, 103: {"name": "魔石怪物伤害加成", "values": [3, 5, 8, 10, 15], "weight": 10}, 104: {"name": "受首领伤害减免", "values": [2, 4, 6, 8, 10], "weight": 8}, 105: {"name": "物理防御无视概率", "values": [1, 2, 3, 5, 7], "weight": 6} } # 检查是否为有效附魔卷轴 static func is_enchant_scroll(vnum: int) -> bool: return vnum in [VNUM_ATTR_ADD, VNUM_ATTR_CHANGE, VNUM_BLESSING_MARBLE, VNUM_RARE_ADD, VNUM_RARE_CHANGE] # 检查物品是否为可附魔装备 static func is_enchantable_item(item: Dictionary) -> bool: if item.is_empty(): return false # 检查是否上锁保护 if item.get("is_locked", false): return false var vnum: int = int(item.get("vnum", 0)) # 箭矢、消耗品不可附魔 (箭矢 8000~8009) if vnum >= 8000 and vnum <= 8009: return false var itype: int = int(item.get("type", 1)) # 默认为 1 (Weapon) 或 2 (Armor) return itype in [1, 2] # 对背包内的装备使用附魔卷轴 func apply_scroll(scroll_slot: int, target_slot: int, inventory: Array, force_success: bool = false) -> Dictionary: if scroll_slot < 0 or scroll_slot >= inventory.size() or inventory[scroll_slot] == null: return {"ok": false, "reason": "INVALID_SCROLL_SLOT", "msg": "附魔卷轴格子无效!"} if target_slot < 0 or target_slot >= inventory.size() or inventory[target_slot] == null: return {"ok": false, "reason": "INVALID_TARGET_SLOT", "msg": "目标装备格子无效!"} var scroll: Dictionary = inventory[scroll_slot] var target: Dictionary = inventory[target_slot] var scroll_vnum: int = int(scroll.get("vnum", 0)) if not is_enchant_scroll(scroll_vnum): return {"ok": false, "reason": "NOT_AN_ENCHANT_SCROLL", "msg": "此物品不是附魔洗炼卷轴!"} if not is_enchantable_item(target): enchant_failed.emit(target_slot, "ITEM_CANNOT_BE_ENCHANTED") return {"ok": false, "reason": "ITEM_CANNOT_BE_ENCHANTED", "msg": "此装备无法进行词条附魔或已被安全上锁!"} if not target.has("attrs"): target["attrs"] = [] if not target.has("rare_attrs"): target["rare_attrs"] = [] var res: Dictionary = {} match scroll_vnum: VNUM_ATTR_ADD: res = _handle_add_attribute(target, force_success) VNUM_ATTR_CHANGE: res = _handle_change_attribute(target) VNUM_BLESSING_MARBLE: res = _handle_blessing_marble(target, force_success) VNUM_RARE_ADD: res = _handle_rare_add(target, force_success) VNUM_RARE_CHANGE: res = _handle_rare_change(target) if not res.get("ok", false): enchant_failed.emit(target_slot, res.get("reason", "FAILED")) return res # 扣除 1 个卷轴 _consume_scroll(scroll_slot, inventory) if res.get("success", false): if scroll_vnum in [VNUM_RARE_ADD, VNUM_RARE_CHANGE]: rare_enchant_applied.emit(target_slot, true, target["rare_attrs"]) else: enchant_applied.emit(target_slot, scroll_vnum, true, target["attrs"]) else: enchant_applied.emit(target_slot, scroll_vnum, false, target["attrs"]) return res # 扣除背包中的卷轴 func _consume_scroll(slot: int, inventory: Array) -> void: var item: Dictionary = inventory[slot] var count: int = int(item.get("count", 1)) if count > 1: item["count"] = count - 1 else: inventory[slot] = null # 71085: 添加第 1~4 条属性 func _handle_add_attribute(target: Dictionary, force_success: bool) -> Dictionary: var attrs: Array = target["attrs"] if attrs.size() >= 4: return {"ok": false, "reason": "MAX_BASE_ATTRS_REACHED", "msg": "该装备已有 4 条属性!请使用祝福宝珠开辟第 5 条属性。"} var rate: int = ADD_PERCENT_TABLE[attrs.size()] var roll: int = randi_range(1, 100) var is_succ: bool = force_success or (roll <= rate) if not is_succ: return {"ok": true, "success": false, "msg": "附魔失败,卷轴化为灰烬,未能追加新属性!"} var new_attr = _roll_random_attribute(attrs, target.get("type", 1)) attrs.append(new_attr) return { "ok": true, "success": true, "new_attr": new_attr, "total_attrs": attrs.size(), "msg": "附魔成功!装备获得了新词条【%s +%d】!" % [new_attr["name"], new_attr["value"]] } # 71084: 改变所有现有 1~5 条属性 func _handle_change_attribute(target: Dictionary) -> Dictionary: var attrs: Array = target["attrs"] if attrs.is_empty(): return {"ok": false, "reason": "NO_ATTRS_TO_CHANGE", "msg": "该装备没有任何属性词条,无法进行洗炼!"} var count: int = attrs.size() attrs.clear() for i in range(count): var attr = _roll_random_attribute(attrs, target.get("type", 1)) attrs.append(attr) return { "ok": true, "success": true, "attrs": attrs, "msg": "洗炼成功!%d 条词条已全新重铸!" % count } # 70024: 祝福宝珠 (添加第 5 条属性) func _handle_blessing_marble(target: Dictionary, force_success: bool) -> Dictionary: var attrs: Array = target["attrs"] if attrs.size() < 4: return {"ok": false, "reason": "NEED_4_ATTRS_FIRST", "msg": "装备必须先拥有 4 条属性,才能使用祝福宝珠!"} if attrs.size() >= 5: return {"ok": false, "reason": "ALREADY_HAS_5_ATTRS", "msg": "该装备已拥有 5 条属性,达到上限!"} var rate: int = ADD_PERCENT_TABLE[4] # 30% var roll: int = randi_range(1, 100) var is_succ: bool = force_success or (roll <= rate) if not is_succ: return {"ok": true, "success": false, "msg": "祝福宝珠破碎,未能为装备附加第 5 条属性!"} var new_attr = _roll_random_attribute(attrs, target.get("type", 1)) attrs.append(new_attr) return { "ok": true, "success": true, "new_attr": new_attr, "total_attrs": 5, "msg": "神圣光芒降临!成功为装备铭刻第 5 条核心属性【%s +%d】!" % [new_attr["name"], new_attr["value"]] } # 71151: 稀有属性附加 (第 6~7 条) func _handle_rare_add(target: Dictionary, force_success: bool) -> Dictionary: var rares: Array = target["rare_attrs"] if rares.size() >= 2: return {"ok": false, "reason": "MAX_RARE_ATTRS", "msg": "已达到 2 条稀有词条上限!"} var roll: int = randi_range(1, 100) var is_succ: bool = force_success or (roll <= RARE_ADD_PERCENT) if not is_succ: return {"ok": true, "success": false, "msg": "稀有附魔失败,未能附加稀有词条!"} var new_rare = _roll_random_rare_attribute(rares) rares.append(new_rare) return { "ok": true, "success": true, "rare_attr": new_rare, "total_rares": rares.size(), "msg": "稀有附魔成功!觉醒了金色稀有词条【%s +%d%%】!" % [new_rare["name"], new_rare["value"]] } # 71152: 稀有属性改变 (单独洗炼第 6~7 条) func _handle_rare_change(target: Dictionary) -> Dictionary: var rares: Array = target["rare_attrs"] if rares.is_empty(): return {"ok": false, "reason": "NO_RARES_TO_CHANGE", "msg": "该装备尚无任何稀有词条!"} var count: int = rares.size() rares.clear() for i in range(count): var r = _roll_random_rare_attribute(rares) rares.append(r) return { "ok": true, "success": true, "rare_attrs": rares, "msg": "稀有词条洗炼成功!%d 条稀有属性已重新激活!" % count } # 生成不重复的普通属性 func _roll_random_attribute(existing_attrs: Array, item_type: int) -> Dictionary: var existing_ids: Array = [] for a in existing_attrs: existing_ids.append(a.get("type", 0)) # 选用武器或防具属性池 var pool = ItemAttrSystem.WEAPON_ATTR_POOL if item_type == 1 else ItemAttrSystem.ARMOR_ATTR_POOL var candidates: Array = [] for type_id in pool.keys(): if not (type_id in existing_ids): candidates.append(type_id) if candidates.is_empty(): candidates = pool.keys() var picked_id: int = candidates[randi() % candidates.size()] var entry = pool[picked_id] var tier_idx: int = randi() % entry["values"].size() var val: int = entry["values"][tier_idx] return { "type": picked_id, "name": entry["name"], "value": val, "tier": tier_idx + 1 } # 生成不重复的稀有属性 func _roll_random_rare_attribute(existing_rares: Array) -> Dictionary: var existing_ids: Array = [] for a in existing_rares: existing_ids.append(a.get("type", 0)) var candidates: Array = [] for type_id in RARE_ATTR_POOL.keys(): if not (type_id in existing_ids): candidates.append(type_id) if candidates.is_empty(): candidates = RARE_ATTR_POOL.keys() var picked_id: int = candidates[randi() % candidates.size()] var entry = RARE_ATTR_POOL[picked_id] var tier_idx: int = randi() % entry["values"].size() var val: int = entry["values"][tier_idx] return { "type": picked_id, "name": entry["name"], "value": val, "tier": tier_idx + 1 }