# polymorph_marble_system.gd —— Metin2 40250 官方变身宝珠与怪物精魂附体系统 1:1 # 对照 40250 服务端 polymorph.cpp, polymorph.h, char.cpp, affect.h class_name PolymorphMarbleSystem extends RefCounted signal polymorph_started(mob_vnum: int, mob_name: String, duration: float, bonus_type: int, bonus_val: int) signal polymorph_ended(mob_vnum: int, mob_name: String) const VNUM_POLYMORPH_MARBLE := 70104 # 变身宝珠 (Polymorph Marble) # 40250 变身法术技能境界 (Skill Master Type) const SKILL_NORMAL := 0 # 普通熟练度 (1~19 级): 10 分钟 (600s) const SKILL_MASTER := 1 # Master (M1~M10): 15 分钟 (900s) const SKILL_GRAND_MASTER := 2 # Grand Master (G1~G10): 20 分钟 (1200s) const SKILL_PERFECT_MASTER := 3 # Perfect Master (P): 25 分钟 (1500s) # 40250 polymorph.h 加成属性类型枚举 const POLYMORPH_NO_BONUS := 0 const POLYMORPH_ATK_BONUS := 1 # 攻击力增益 (POINT_ATT_BONUS) const POLYMORPH_DEF_BONUS := 2 # 防御力增益 (POINT_DEF_BONUS) const POLYMORPH_SPD_BONUS := 3 # 移动速度增益 (POINT_MOV_SPEED) # 40250 经典怪物精魂图鉴与加成配置表 const MONSTER_POLY_TABLE: Dictionary = { 501: { "mob_vnum": 501, "name": "野蛮步兵", "bonus_type": POLYMORPH_ATK_BONUS, "bonus_val": 40, "stat_key": "attack_power" }, 502: { "mob_vnum": 502, "name": "野蛮弓手", "bonus_type": POLYMORPH_ATK_BONUS, "bonus_val": 35, "stat_key": "attack_power" }, 492: { "mob_vnum": 492, "name": "白发蜘蛛", "bonus_type": POLYMORPH_DEF_BONUS, "bonus_val": 50, "stat_key": "defense" }, 101: { "mob_vnum": 101, "name": "野狗", "bonus_type": POLYMORPH_SPD_BONUS, "bonus_val": 25, "stat_key": "move_speed" }, 1901: { "mob_vnum": 1901, "name": "九尾妖狐", "bonus_type": POLYMORPH_SPD_BONUS, "bonus_val": 30, "stat_key": "move_speed" } } var is_polymorphed: bool = false var active_mob_vnum: int = 0 var active_mob_name: String = "" var time_remaining: float = 0.0 var total_duration: float = 0.0 var active_bonus_type: int = POLYMORPH_NO_BONUS var active_bonus_val: int = 0 var active_stat_key: String = "" # 计算变身持续时长 (40250 polymorph.cpp:44-59) static func get_duration_by_mastery(master_type: int) -> float: match master_type: SKILL_NORMAL: return 600.0 # 10 分钟 SKILL_MASTER: return 900.0 # 15 分钟 SKILL_GRAND_MASTER: return 1200.0 # 20 分钟 SKILL_PERFECT_MASTER: return 1500.0 # 25 分钟 _: return 600.0 # 使用变身宝珠进行怪物附体变身 func polymorph_character(marble_item: Dictionary, skill_mastery: int, player_stats: Dictionary) -> Dictionary: var vnum := int(marble_item.get("vnum", 0)) if vnum != VNUM_POLYMORPH_MARBLE: return {"ok": false, "reason": "NOT_A_POLYMORPH_MARBLE", "msg": "该物品不是变身宝珠!"} var mob_vnum := int(marble_item.get("mob_vnum", 0)) if mob_vnum == 0: var sockets: Array = marble_item.get("sockets", []) if not sockets.is_empty(): mob_vnum = int(sockets[0]) if not MONSTER_POLY_TABLE.has(mob_vnum): return {"ok": false, "reason": "INVALID_MONSTER_VNUM", "msg": "未知的变身怪物精魂!"} # 若当前已处于变身状态,先恢复原形 if is_polymorphed: revert_polymorph(player_stats) var mob_info: Dictionary = MONSTER_POLY_TABLE[mob_vnum] var duration: float = get_duration_by_mastery(skill_mastery) is_polymorphed = true active_mob_vnum = mob_vnum active_mob_name = mob_info["name"] time_remaining = duration total_duration = duration active_bonus_type = int(mob_info["bonus_type"]) active_bonus_val = int(mob_info["bonus_val"]) active_stat_key = str(mob_info["stat_key"]) # 注入变身属性加成 if not active_stat_key.is_empty() and active_bonus_val > 0: player_stats[active_stat_key] = int(player_stats.get(active_stat_key, 0)) + active_bonus_val polymorph_started.emit(active_mob_vnum, active_mob_name, duration, active_bonus_type, active_bonus_val) return { "ok": true, "mob_vnum": active_mob_vnum, "mob_name": active_mob_name, "duration": duration, "bonus_type": active_bonus_type, "bonus_val": active_bonus_val, "msg": "怪物精魂附体!成功变身为【%s】,持续 %.0f 秒。" % [active_mob_name, duration] } # 解除变身恢复真身原型 func revert_polymorph(player_stats: Dictionary) -> Dictionary: if not is_polymorphed: return {"ok": false, "reason": "NOT_POLYMORPHED", "msg": "当前未处于变身状态!"} # 清除施加的加成属性 if not active_stat_key.is_empty() and active_bonus_val > 0: player_stats[active_stat_key] = int(player_stats.get(active_stat_key, 0)) - active_bonus_val var old_mob := active_mob_vnum var old_name := active_mob_name is_polymorphed = false active_mob_vnum = 0 active_mob_name = "" time_remaining = 0.0 total_duration = 0.0 active_bonus_type = POLYMORPH_NO_BONUS active_bonus_val = 0 active_stat_key = "" polymorph_ended.emit(old_mob, old_name) return { "ok": true, "mob_vnum": old_mob, "mob_name": old_name, "msg": "变身时效已过,恢复人物原形。" } # 逻辑时钟心跳 func update(delta: float, player_stats: Dictionary) -> void: if not is_polymorphed: return time_remaining -= delta if time_remaining <= 0.0: revert_polymorph(player_stats) # 40250 行为限制检查:变身期间禁止乘骑坐骑 func can_mount_horse() -> bool: return not is_polymorphed # 40250 行为限制检查:变身期间禁止释放原生职业技能 func can_cast_player_skills() -> bool: return not is_polymorphed # 序列化 func serialize() -> Dictionary: return { "is_polymorphed": is_polymorphed, "active_mob_vnum": active_mob_vnum, "active_mob_name": active_mob_name, "time_remaining": time_remaining, "total_duration": total_duration, "active_bonus_type": active_bonus_type, "active_bonus_val": active_bonus_val, "active_stat_key": active_stat_key } # 反序列化 func deserialize(data: Dictionary) -> void: is_polymorphed = bool(data.get("is_polymorphed", false)) active_mob_vnum = int(data.get("active_mob_vnum", 0)) active_mob_name = str(data.get("active_mob_name", "")) time_remaining = float(data.get("time_remaining", 0.0)) total_duration = float(data.get("total_duration", 0.0)) active_bonus_type = int(data.get("active_bonus_type", POLYMORPH_NO_BONUS)) active_bonus_val = int(data.get("active_bonus_val", 0)) active_stat_key = str(data.get("active_stat_key", ""))