# skill_book_reading_system.gd —— 40250 官方大师技能书悟道研读与突破系统 1:1 # 严格对照: # metin2/src/server/game/src/char_skill.cpp:416-560 (CHARACTER::LearnSkillByBook) # metin2/src/server/game/src/char_item.cpp:2128-2160 (ITEM_SKILLBOOK / 50300) # metin2/src/server/game/src/affect.h (AFFECT_SKILL_BOOK_BONUS 512, AFFECT_SKILL_NO_BOOK_DELAY 513) # metin2/src/server/share/conf/item_proto.txt (71001 驱魔卷轴, 71094 隐士之药) extends RefCounted const ITEM_SKILLBOOK_VNUM := 50300 const EXORCISM_SCROLL_VNUM := 71001 # 驱魔卷轴: AFFECT_SKILL_NO_BOOK_DELAY const HERMIT_ADVICE_VNUM := 71094 # 隐士之药: AFFECT_SKILL_BOOK_BONUS const EXP_COST := 20000 # 40250 char_skill.cpp:430 need_exp = 20000 const COOLDOWN_DURATION := 86400 # 24小时冷却 (LC_IsKorea 86400 秒) const BASE_SUCCESS_RATE := 35 # 基础成功率 35% (char_skill.cpp:524: percent = 65 -> 100 - 65 = 35%) # 技能进阶档次 (MasterType) const SKILL_NORMAL := 0 # Lv 1 - 19 const SKILL_MASTER := 1 # M1 (Lv 20) ~ M10 (Lv 29) const SKILL_GRAND_MASTER := 2 # G1 (Lv 30) ~ G10 (Lv 39) const SKILL_PERFECT_MASTER := 3 # P (Lv 40) # 角色技能书研读状态 var skills: Dictionary = {} # skill_id -> {"level": int, "read_count": int, "next_read_time": int} var affects: Dictionary = {} # affect_type -> bool var player_exp: int = 100000 var current_time: int = 1000000 # 累计统计 var total_books_read: int = 0 var total_books_succeeded: int = 0 var total_books_failed: int = 0 func _init(initial_exp: int = 100000, initial_time: int = 1000000) -> void: player_exp = initial_exp current_time = initial_time skills = {} affects = {} total_books_read = 0 total_books_succeeded = 0 total_books_failed = 0 # 注册/初始化技能 func init_skill(skill_id: int, level: int = 20, read_count: int = 0, next_read_time: int = 0) -> void: skills[skill_id] = { "level": level, "read_count": read_count, "next_read_time": next_read_time } # 获取技能档次 func get_skill_master_type(skill_id: int) -> int: if not skills.has(skill_id): return SKILL_NORMAL var lvl: int = skills[skill_id]["level"] if lvl < 20: return SKILL_NORMAL elif lvl < 30: return SKILL_MASTER elif lvl < 40: return SKILL_GRAND_MASTER else: return SKILL_PERFECT_MASTER # 计算升下一级所需的成功书本数 (char_skill.cpp:509 need_bookcount = level - 20) # M1(Lv20) 升 M2: 需 1 本 (20 - 20 + 1 = 1) # M2(Lv21) 升 M3: 需 2 本 # ... # M10(Lv29) 升 G1: 需 10 本 # 累计突破至 G 需 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = 55 本成功! func get_need_books_for_next_level(skill_id: int) -> int: if not skills.has(skill_id): return 0 var lvl: int = skills[skill_id]["level"] if lvl < 20 or lvl >= 30: return 0 return lvl - 20 + 1 # 使用驱魔卷轴 (71001) func use_exorcism_scroll() -> bool: affects[EXORCISM_SCROLL_VNUM] = true return true # 使用隐士之药 (71094) func use_hermit_advice() -> bool: affects[HERMIT_ADVICE_VNUM] = true return true # 检查是否存在状态 func has_affect(affect_vnum: int) -> bool: return affects.get(affect_vnum, false) # 研读技能书核心方法 (1:1 CHARACTER::LearnSkillByBook) # roll_override: 传入 1~100 用于单元测试确定性判定,-1 表示根据随机数判定 func learn_skill_by_book(skill_id: int, book_socket_skill_vnum: int = -1, roll_override: int = -1) -> Dictionary: var result := { "success": false, "level_up": false, "breakthrough_g": false, "error_code": "OK", "read_count": 0, "needed_books": 0, "remaining_books": 0, "current_level": 0, "exp_deducted": 0, "consumed_exorcism": false, "consumed_hermit": false, "message": "" } # 1. 校验技能是否存在 if not skills.has(skill_id): result["error_code"] = "NOT_LEARNABLE" result["message"] = "无法研读未掌握或非本流派的技能。" return result # 2. 校验技能书 Socket 绑定的技能编号 (40250 char_item.cpp:2132) if book_socket_skill_vnum != -1 and book_socket_skill_vnum != skill_id: result["error_code"] = "SKILL_MISMATCH" result["message"] = "该技能书并非此技能专研典籍。" return result var skill_data: Dictionary = skills[skill_id] var current_lvl: int = skill_data["level"] result["current_level"] = current_lvl # 3. 校验阶档 var master_type: int = get_skill_master_type(skill_id) if master_type < SKILL_MASTER: result["error_code"] = "NOT_MASTER_TIER" result["message"] = "此技能尚未达到大师 (M) 阶档,无法研读书籍。" return result elif master_type >= SKILL_GRAND_MASTER: result["error_code"] = "ALREADY_G_OR_P" result["message"] = "此技能已达到宗师 (G) 阶或更高,书籍无法再提升造诣。" return result # 4. 经验值检查与消耗 (char_skill.cpp:430: need_exp = 20000) if player_exp < EXP_COST: result["error_code"] = "INSUFFICIENT_EXP" result["message"] = "角色经验值不足 20,000,精神无法专注研读。" return result # 5. 冷却时间与驱魔卷轴检查 (char_skill.cpp:455) var next_time: int = skill_data.get("next_read_time", 0) var bypass_cooldown := false if current_time < next_time: if has_affect(EXORCISM_SCROLL_VNUM): affects.erase(EXORCISM_SCROLL_VNUM) bypass_cooldown = true result["consumed_exorcism"] = true else: result["error_code"] = "COOLDOWN_ACTIVE" result["message"] = "心智尚需沉淀,请在冷却结束后再读,或使用驱魔卷轴。" return result # 扣除 20,000 EXP 并产生 24 小时冷却 (86,400 秒) player_exp -= EXP_COST result["exp_deducted"] = EXP_COST skill_data["next_read_time"] = current_time + COOLDOWN_DURATION total_books_read += 1 # 6. 成功率计算与隐士之药加成 var success_chance: int = BASE_SUCCESS_RATE if has_affect(HERMIT_ADVICE_VNUM): affects.erase(HERMIT_ADVICE_VNUM) success_chance = 100 # 隐士之药 100% 保底成功 (char_skill.cpp:527) result["consumed_hermit"] = true var roll := roll_override if roll_override > 0 else (randi() % 100 + 1) var is_read_success: bool = (roll <= success_chance) var need_books: int = get_need_books_for_next_level(skill_id) result["needed_books"] = need_books if not is_read_success: # 研读失败 (char_skill.cpp:613 READ_FAIL) total_books_failed += 1 result["success"] = false result["read_count"] = skill_data["read_count"] result["remaining_books"] = need_books - skill_data["read_count"] result["error_code"] = "READ_FAIL" result["message"] = "研读失败:经脉运转不顺,书中奥义未能参透。" return result # 研读成功 total_books_succeeded += 1 result["success"] = true var cur_count: int = skill_data["read_count"] + 1 if cur_count >= need_books: # 晋级提升一阶等级!(SkillLevelUp) skill_data["level"] += 1 skill_data["read_count"] = 0 result["level_up"] = true result["current_level"] = skill_data["level"] result["read_count"] = 0 result["remaining_books"] = 0 if skill_data["level"] >= 30: result["breakthrough_g"] = true result["message"] = "顿悟成功!技能历经千锤百炼,成功突破至宗师境界 (G1)!" else: result["message"] = "顿悟成功!技能境界提升至 M%d!" % (skill_data["level"] - 19) else: # 累积研读进度 skill_data["read_count"] = cur_count result["read_count"] = cur_count result["remaining_books"] = need_books - cur_count result["message"] = "心领神会!还需研读 %d 本成功即可突破进阶。" % (need_books - cur_count) return result