# dragon_soul_system.gd —— Metin2 40250 龙神炼金石系统 1:1 # 对照 40250 服务端 DragonSoul.cpp, char_dragonsoul.cpp 及客户端 uidragonsoul.py class_name DragonSoulSystem extends RefCounted signal deck_activated(deck_idx: int) signal deck_deactivated(deck_idx: int) # 6 种官方龙神石类型 (DragonSoul.cpp:EDSStoneTypes) enum DragonStoneType { NONE = 0, DIAMOND = 1, # 钻石: INT, 魔法抗性 RUBY = 2, # 红宝石: STR, 物理攻击力, 防御力 JADE = 3, # 玉石: Max HP, HP 恢复 SAPPHIRE = 4,# 蓝宝石: DEX, 职业减伤 GARNET = 5, # 石榴石: CON, Max SP ONYX = 6 # 缟玛瑙: 格挡, 反弹, 穿透抵抗 } # 5 档品阶 (Grade) enum Grade { ROUGH = 0, # 粗糙 CUT = 1, # 切割 RARE = 2, # 稀有 ANCIENT = 3, # 古代 LEGENDARY = 4 # 传奇 } # 5 档净度 (Clarity) enum Clarity { MATT = 0, # 哑光 CLEAR = 1, # 清晰 FLAWLESS = 2, # 无瑕 BRILLIANT = 3, # 辉煌 EXCELLENT = 4 # 卓越 } const DECK_SKY := 0 # 天空卡槽 const DECK_EARTH := 1 # 大地卡槽 const DECK_COUNT := 2 const SLOTS_PER_DECK := 6 # 每卡槽 6 个神石槽位 # 双卡槽数据结构: decks[deck_idx][slot_idx] = stone_dict or null var decks: Array[Array] = [[], []] var active_deck: int = -1 # -1: 未激活, 0: 天空卡槽, 1: 大地卡槽 func _init() -> void: for d in range(DECK_COUNT): var slot_list: Array = [] for s in range(SLOTS_PER_DECK): slot_list.append(null) decks[d] = slot_list # 创建一颗龙神石 static func create_dragon_stone(type: int, grade: int = 0, clarity: int = 0, refine: int = 0, duration: float = 86400.0) -> Dictionary: var stone: Dictionary = { "stone_type": type, "grade": clampi(grade, 0, 4), "clarity": clampi(clarity, 0, 4), "refine": clampi(refine, 0, 6), "duration": duration, # 激活消耗时间 (秒) "total_duration": duration } stone["attributes"] = calculate_stone_attributes(stone) return stone # 计算单颗神石属性 (对齐 40250 DragonSoulTable.txt) static func calculate_stone_attributes(stone: Dictionary) -> Dictionary: var type: int = int(stone.get("stone_type", 0)) var gr: int = int(stone.get("grade", 0)) var cl: int = int(stone.get("clarity", 0)) var rf: int = int(stone.get("refine", 0)) var attrs: Dictionary = {} match type: DragonStoneType.DIAMOND: attrs["int_bonus"] = 5 + (gr * 3) + (cl * 2) + rf attrs["magic_defense"] = 2 + (gr * 2) + (cl * 2) + (rf * 2) DragonStoneType.RUBY: attrs["str_bonus"] = 5 + (gr * 3) + (cl * 2) + rf attrs["att_grade"] = 20 + (gr * 15) + (cl * 10) + (rf * 5) attrs["def_grade"] = 15 + (gr * 10) + (cl * 5) + (rf * 4) DragonStoneType.JADE: attrs["max_hp"] = 300 + (gr * 250) + (cl * 150) + (rf * 100) attrs["hp_recovery_pct"] = 3 + gr + cl + rf DragonStoneType.SAPPHIRE: attrs["dex_bonus"] = 5 + (gr * 3) + (cl * 2) + rf attrs["resist_warrior"] = 2 + gr + cl + rf attrs["resist_assassin"] = 2 + gr + cl + rf DragonStoneType.GARNET: attrs["con_bonus"] = 5 + (gr * 3) + (cl * 2) + rf attrs["max_sp"] = 200 + (gr * 150) + (cl * 100) + (rf * 50) DragonStoneType.ONYX: attrs["block_pct"] = 2 + (gr * 2) + cl + rf attrs["reflect_pct"] = 2 + (gr * 2) + cl + rf return attrs # 装备神石到卡槽 func equip_stone(deck_idx: int, stone: Dictionary) -> Dictionary: if deck_idx < 0 or deck_idx >= DECK_COUNT: return {"ok": false, "reason": "INVALID_DECK"} var type: int = int(stone.get("stone_type", 0)) if type < 1 or type > 6: return {"ok": false, "reason": "INVALID_STONE_TYPE"} var slot_idx: int = type - 1 # 1~6 映射到 0~5 号槽位 decks[deck_idx][slot_idx] = stone return { "ok": true, "deck": deck_idx, "slot": slot_idx, "stone": stone } # 卸下神石 func unequip_stone(deck_idx: int, slot_idx: int) -> Dictionary: if deck_idx < 0 or deck_idx >= DECK_COUNT: return {"ok": false, "reason": "INVALID_DECK"} if slot_idx < 0 or slot_idx >= SLOTS_PER_DECK: return {"ok": false, "reason": "INVALID_SLOT"} var removed = decks[deck_idx][slot_idx] decks[deck_idx][slot_idx] = null return {"ok": true, "stone": removed} # 激活/停用卡槽 func toggle_deck(deck_idx: int) -> bool: if active_deck == deck_idx: active_deck = -1 deck_deactivated.emit(deck_idx) return false else: if active_deck != -1: deck_deactivated.emit(active_deck) active_deck = deck_idx deck_activated.emit(deck_idx) return true # 计算当前已激活卡槽的总战力属性 func get_active_bonuses() -> Dictionary: var total_bonuses: Dictionary = {} if active_deck < 0 or active_deck >= DECK_COUNT: return total_bonuses var deck: Array = decks[active_deck] for slot in deck: if slot != null and float(slot.get("duration", 0.0)) > 0.0: var attrs: Dictionary = slot.get("attributes", {}) for key in attrs: total_bonuses[key] = int(total_bonuses.get(key, 0)) + int(attrs[key]) return total_bonuses # 逐帧消耗激活中的龙神石能量时间 func update(dt: float) -> Array: var expired_stones: Array = [] if active_deck < 0 or active_deck >= DECK_COUNT: return expired_stones var deck: Array = decks[active_deck] for i in range(deck.size()): var stone = deck[i] if stone != null: var dur: float = float(stone.get("duration", 0.0)) dur -= dt if dur <= 0.0: dur = 0.0 expired_stones.append({"deck": active_deck, "slot": i, "stone": stone}) stone["duration"] = dur return expired_stones # 升阶 (Grade Refine): 2 颗同种类、同品阶神石融合升级 static func refine_grade(stone_a: Dictionary, stone_b: Dictionary, force_success: bool = false) -> Dictionary: var ta: int = int(stone_a.get("stone_type", 0)) var tb: int = int(stone_b.get("stone_type", 0)) var ga: int = int(stone_a.get("grade", 0)) var gb: int = int(stone_b.get("grade", 0)) if ta != tb or ga != gb: return {"ok": false, "reason": "MISMATCHED_STONES", "msg": "只有同种类且同品阶的神石才能融合升阶!"} if ga >= Grade.LEGENDARY: return {"ok": false, "reason": "MAX_GRADE", "msg": "该神石已达到最高传奇品阶!"} # 成功率 60% var success: bool = force_success or randf() < 0.60 if success: var new_stone = create_dragon_stone(ta, ga + 1, 0, 0) return {"ok": true, "success": true, "stone": new_stone, "msg": "神石品阶提升成功!"} else: return {"ok": true, "success": false, "msg": "升阶失败,融合材料已碎裂。"} # 升净度 (Clarity Refine): 2 颗同种类、同品阶、同净度神石融合升级 static func refine_clarity(stone_a: Dictionary, stone_b: Dictionary, force_success: bool = false) -> Dictionary: var ta: int = int(stone_a.get("stone_type", 0)) var tb: int = int(stone_b.get("stone_type", 0)) var ca: int = int(stone_a.get("clarity", 0)) var cb: int = int(stone_b.get("clarity", 0)) if ta != tb or ca != cb: return {"ok": false, "reason": "MISMATCHED_STONES", "msg": "只有同种类且同净度的神石才能融合提升净度!"} if ca >= Clarity.EXCELLENT: return {"ok": false, "reason": "MAX_CLARITY", "msg": "该神石已达到最高卓越净度!"} var success: bool = force_success or randf() < 0.50 if success: var ga: int = int(stone_a.get("grade", 0)) var new_stone = create_dragon_stone(ta, ga, ca + 1, 0) return {"ok": true, "success": true, "stone": new_stone, "msg": "神石净度提升成功!"} else: return {"ok": true, "success": false, "msg": "净度提升失败,辅助材料碎裂。"}