# skill_book_system.gd —— 40250 技能书研读与技能突破进阶系统 1:1 规则引擎 # 严格对照: # metin2/src/server/game/src/char_item.cpp:2128-2160 (ITEM_SKILLBOOK / 50300) # metin2/src/server/game/src/char_skill.cpp:416-570 (CHARACTER::LearnSkillByBook) # metin2/src/server/game/src/char_item.cpp:1657 (Soul Stone 50513 / G->P) # ClientVS22/UserInterface/Packet.h extends RefCounted const SKILL_BOOK_VNUM := 50300 const EXORCISM_SCROLL_VNUM := 71001 # 驱魔卷轴 (AFFECT_SKILL_NO_BOOK_DELAY) const HERMIT_ADVICE_VNUM := 71094 # 隐士教训 (AFFECT_SKILL_BOOK_BONUS) const SOUL_STONE_VNUM := 71001 # 魂石 (50513) const SKILL_BOOK_EXP_COST := 20000 # 40250 char_skill.cpp:430 need_exp = 20000 const SKILL_BOOK_DELAY := 86400 # 24 小时冷却 (LC_IsKorea 86400s) # 40250 MasterType 枚举 const MASTER_NORMAL := 0 # Lv 1 - 20 const MASTER_M := 1 # M1 - M10 (Lv 21 - 30) const MASTER_G := 2 # G1 - G10 (Lv 31 - 40) const MASTER_P := 3 # Perfect Master (Lv 40) # 错误码 enum Result { SUCCESS_LEVEL_UP, # 成功并升级(或突破到 G) SUCCESS_READ_ONCE, # 成功研读一本(累积进度) FAIL_READ, # 研读失败 ERR_NOT_LEARNABLE, # 非本职业/未入流派技能 ERR_NOT_MASTER_TIER, # 尚未达到 M 阶 (Lv < 20) ERR_ALREADY_G_OR_P, # 已达到 G 阶或更高,无法再读技能书 ERR_INSUFFICIENT_EXP, # 经验不足 20,000 ERR_COOLDOWN, # 24小时冷却中 } # 魂石善恶值消耗表 (char_skill.cpp / training_grandmaster_skill.quest) const SOUL_STONE_KARMA_COST := { 1: 1000, 2: 1500, 3: 2000, 4: 2500, 5: 3000, 6: 3500, 7: 4000, 8: 4500, 9: 5000, 10: 5500 } # 判定技能书升级所需本数:40250 char_skill.cpp:509 need_bookcount = GetSkillLevel(dwSkillVnum) - 20 static func get_need_books(skill_level: int) -> int: # M1 (21) 需 1 本,M2 (22) 需 2 本 ... M10 (30) 需 10 本 return maxi(1, skill_level - 20) # 研读条件前置校验 static func check_can_read( skill_id: int, skill_level: int, master_type: int, player_exp: int, next_read_time: int, current_time: int, has_exorcism: bool ) -> int: if skill_id <= 0: return Result.ERR_NOT_LEARNABLE if master_type < MASTER_M or skill_level < 20: return Result.ERR_NOT_MASTER_TIER if master_type > MASTER_M or skill_level >= 30: return Result.ERR_ALREADY_G_OR_P if player_exp < SKILL_BOOK_EXP_COST: return Result.ERR_INSUFFICIENT_EXP if current_time < next_read_time and not has_exorcism: return Result.ERR_COOLDOWN return 0 # OK # 研读技能书核心判定逻辑(1:1 char_skill.cpp:488-570) static func read_skill_book( skill_id: int, skill_level: int, master_type: int, read_count: int, player_exp: int, next_read_time: int, current_time: int, has_exorcism: bool, has_hermit: bool, roll_val := -1 # 测试可注入 1..100 ) -> Dictionary: var err := check_can_read(skill_id, skill_level, master_type, player_exp, next_read_time, current_time, has_exorcism) if err != 0: return { "result": err, "skill_id": skill_id, "level": skill_level, "master_type": master_type, "read_count": read_count, "exp_consumed": 0, "next_read_time": next_read_time, "consumed_exorcism": false, "consumed_hermit": false, } var consumed_exorcism := false if current_time < next_read_time and has_exorcism: consumed_exorcism = true var consumed_hermit := false var fail_percent := 65 # 40250 char_skill.cpp:525 int percent = 65; if has_hermit: fail_percent = 0 # 100% 成功 consumed_hermit = true var dice := roll_val if roll_val > 0 else (randi() % 100 + 1) var success := (dice > fail_percent) var new_level := skill_level var new_master := master_type var new_read_count := read_count var new_next_time := current_time + SKILL_BOOK_DELAY var res := Result.FAIL_READ if success: var need_books := get_need_books(skill_level) if read_count + 1 >= need_books: # 升级! new_level += 1 new_read_count = 0 if new_level >= 30: new_master = MASTER_G # 突破到 G1 res = Result.SUCCESS_LEVEL_UP else: new_read_count += 1 res = Result.SUCCESS_READ_ONCE return { "result": res, "skill_id": skill_id, "level": new_level, "master_type": new_master, "read_count": new_read_count, "exp_consumed": SKILL_BOOK_EXP_COST, "next_read_time": new_next_time, "consumed_exorcism": consumed_exorcism, "consumed_hermit": consumed_hermit, "need_books": get_need_books(new_level), } # 魂石修炼逻辑(1:1 G1..G10 -> P) static func soul_stone_train( skill_id: int, skill_level: int, master_type: int, current_karma: int, roll_val := -1 ) -> Dictionary: if master_type != MASTER_G or skill_level < 30 or skill_level >= 40: return {"success": false, "err": "not_g_tier"} var g_step := skill_level - 30 # 1..10 var base_cost: int = SOUL_STONE_KARMA_COST.get(g_step, 1000) var actual_cost: int = base_cost if current_karma >= 0 else (base_cost * 2) var dice := roll_val if roll_val > 0 else (randi() % 100 + 1) # 40250 魂石成功率约 30% var success := (dice <= 30) var new_level := skill_level var new_master := master_type if success: new_level += 1 if new_level >= 40: new_master = MASTER_P return { "success": success, "skill_id": skill_id, "level": new_level, "master_type": new_master, "karma_consumed": actual_cost, } # 格式化官方提示文本 static func get_result_message(res_dict: Dictionary) -> String: match res_dict.get("result", -1): Result.SUCCESS_LEVEL_UP: if res_dict.get("master_type") == MASTER_G and res_dict.get("level") == 30: return "领悟了大宗师的奥秘!技能已成功突破至大宗师(G1)!" return "完全理解了书中内容,技能成功提升到了新的境界!" Result.SUCCESS_READ_ONCE: var remaining := int(res_dict.get("need_books", 1)) - int(res_dict.get("read_count", 0)) return "成功领悟了部分技巧!还需要成功研读 %d 本书以完成突破。" % remaining Result.FAIL_READ: return "研读失败,未能领悟书中的奥秘。" Result.ERR_NOT_LEARNABLE: return "无法修炼该技能书。" Result.ERR_NOT_MASTER_TIER: return "这个技能还未达到大师级别(M),不能通过技能书修炼。" Result.ERR_ALREADY_G_OR_P: return "这个技能已达到大宗师或以上级别,无法再通过普通技能书提升。" Result.ERR_INSUFFICIENT_EXP: return "经验值不足(需要 20,000 EXP)。" Result.ERR_COOLDOWN: var remaining_s := maxi(0, int(res_dict.get("next_read_time", 0))) return "当前处于研读冷却中,请使用驱魔卷轴消除冷却或稍后再试。" _: return ""