# dragon_lair_system.gd —— Metin2 40250 冰龙贝兰-塞陶挑战巢穴 1:1 # 对照 40250 服务端 dragon_lair.quest, dungeon.cpp, char_battle.cpp, mob 2493, NPC 30121 class_name DragonLairSystem extends RefCounted signal dungeon_started(time_limit: float) signal metin_destroyed(metin_vnum: int, metin_name: String) signal minions_spawned(count: int, mob_vnum: int) signal dragon_hp_changed(current_hp: int, max_hp: int) signal dragon_defeated(drops: Array) signal dungeon_failed(reason: String) const NPC_GHOST_OF_SURA := 30121 # 修罗鬼魂 const ITEM_TWISTED_KEY := 30179 # 扭曲钥匙 const KEY_REQUIRED_COUNT := 3 const MIN_LEVEL := 75 const TIME_LIMIT := 3600.0 # 60 分钟限时 const BOSS_VNUM := 2493 # 贝兰-塞陶 (Beran-Setaou) const BOSS_MAX_HP := 800000 const BOSS_BASE_ATK := 1800 const BOSS_BASE_DEF := 650 const METIN_TABLE: Dictionary = { 8031: {"name": "傲慢之石", "desc": "提供 30% 物理抗性减免"}, 8032: {"name": "寂寞之石", "desc": "提供生命自然恢复"}, 8033: {"name": "平静之石", "desc": "提供 30% 魔法抗性减免"}, 8034: {"name": "复仇之石", "desc": "提供 40% 攻击力增幅"} } var is_active: bool = false var remaining_time: float = 0.0 var dragon_hp: int = 0 var dragon_max_hp: int = BOSS_MAX_HP var is_dragon_alive: bool = false var active_metins: Dictionary = {} # vnum -> bool (true = alive) var active_minions: Array = [] var regen_timer: float = 0.0 # 进入冰龙巢穴 (通过 NPC 30121 验证) func enter_lair(player_level: int, inventory: Array) -> Dictionary: if player_level < MIN_LEVEL: return { "ok": false, "reason": "LEVEL_TOO_LOW", "msg": "你的等级不足 75 级,无法承受冰龙巢穴的严寒!" } # 检查背包中的 3 把扭曲钥匙 (30179) var key_slots: Array = [] var total_keys: int = 0 for i in range(inventory.size()): var item = inventory[i] if item != null and int(item.get("vnum", 0)) == ITEM_TWISTED_KEY: var cnt: int = int(item.get("count", 1)) total_keys += cnt key_slots.append({"slot": i, "count": cnt}) if total_keys < KEY_REQUIRED_COUNT: return { "ok": false, "reason": "MISSING_KEYS", "current_keys": total_keys, "required_keys": KEY_REQUIRED_COUNT, "msg": "进入冰龙巢穴需要 3 把扭曲钥匙!你当前拥有 %d 把。" % total_keys } # 扣除 3 把扭曲钥匙 var needed: int = KEY_REQUIRED_COUNT for ks in key_slots: var slot_idx: int = ks["slot"] var available: int = ks["count"] if available <= needed: needed -= available inventory[slot_idx] = null else: inventory[slot_idx]["count"] = available - needed needed = 0 if needed <= 0: break # 初始化巢穴状态 is_active = true remaining_time = TIME_LIMIT dragon_hp = BOSS_MAX_HP dragon_max_hp = BOSS_MAX_HP is_dragon_alive = true active_minions.clear() regen_timer = 0.0 # 刷新 4 块龙神魔石 active_metins.clear() for vnum in METIN_TABLE.keys(): active_metins[vnum] = true dungeon_started.emit(remaining_time) return { "ok": true, "time_limit": remaining_time, "dragon_hp": dragon_hp, "metins": active_metins.duplicate(), "msg": "已使用 3 把扭曲钥匙,成功开启冰龙巢穴!限时 60 分钟!" } # 获取当前冰龙实际攻击力 (受 8034 复仇之石影响) func get_dragon_atk() -> int: var atk := BOSS_BASE_ATK if active_metins.get(8034, false): atk = int(atk * 1.4) # +40% ATK return atk # 获取当前冰龙防御力 func get_dragon_def() -> int: return BOSS_BASE_DEF # 击破魔石机制 func destroy_metin(metin_vnum: int) -> Dictionary: if not is_active: return {"ok": false, "reason": "DUNGEON_NOT_ACTIVE"} if not active_metins.get(metin_vnum, false): return {"ok": false, "reason": "METIN_ALREADY_DESTROYED"} active_metins[metin_vnum] = false var mname: String = METIN_TABLE[metin_vnum]["name"] # 击破魔石唤醒 4 只塞陶龙宫护卫 (vnum: 2401) var spawn_count := 4 for i in range(spawn_count): active_minions.append({"vnum": 2401, "hp": 30000}) metin_destroyed.emit(metin_vnum, mname) minions_spawned.emit(spawn_count, 2401) return { "ok": true, "metin_vnum": metin_vnum, "metin_name": mname, "remaining_metins": get_alive_metin_count(), "spawned_minions": spawn_count, "msg": "【%s】已被击破!对应龙神加成已破除,但唤醒了龙宫护卫!" % mname } # 获取存活魔石数量 func get_alive_metin_count() -> int: var count := 0 for v in active_metins.values(): if v: count += 1 return count # 对冰龙造成伤害 func apply_damage(raw_dmg: int, is_magic: bool = false) -> Dictionary: if not is_active or not is_dragon_alive: return {"ok": false, "reason": "DRAGON_NOT_ALIVE"} var def := get_dragon_def() var net_dmg: float = max(1, raw_dmg - def) # 8031 傲慢之石减免 30% 物理伤害 if not is_magic and active_metins.get(8031, false): net_dmg *= 0.70 # 8033 平静之石减免 30% 魔法伤害 if is_magic and active_metins.get(8033, false): net_dmg *= 0.70 var final_dmg := int(round(net_dmg)) dragon_hp = max(0, dragon_hp - final_dmg) dragon_hp_changed.emit(dragon_hp, dragon_max_hp) # 击杀冰龙判定 if dragon_hp <= 0: is_dragon_alive = false is_active = false var drops := _generate_dragon_drops() dragon_defeated.emit(drops) return { "ok": true, "killed": true, "net_dmg": final_dmg, "remaining_hp": 0, "drops": drops, "msg": "【冰龙贝兰-塞陶】已被彻底击败!龙鳞与龙爪散落一地!" } return { "ok": true, "killed": false, "net_dmg": final_dmg, "remaining_hp": dragon_hp, "hp_ratio": float(dragon_hp) / float(dragon_max_hp) } # 逐帧更新 (计时与 8032 寂寞之石生命回复) func update(dt: float) -> void: if not is_active: return remaining_time -= dt if remaining_time <= 0.0: is_active = false is_dragon_alive = false dungeon_failed.emit("TIME_OUT") return # 8032 寂寞之石:每 5 秒为冰龙回复 2% 最大生命 (16000 HP) if is_dragon_alive and active_metins.get(8032, false): regen_timer += dt if regen_timer >= 5.0: regen_timer = 0.0 var heal_amount := int(BOSS_MAX_HP * 0.02) dragon_hp = mini(BOSS_MAX_HP, dragon_hp + heal_amount) dragon_hp_changed.emit(dragon_hp, dragon_max_hp) # 生成冰龙掉落物 (71123 龙鳞, 71129 龙爪, 50186 水龙宝箱) func _generate_dragon_drops() -> Array: var drops: Array = [] # 1. 必掉史诗升阶材料:龙鳞 (71123) drops.append({ "vnum": 71123, "name": "龙鳞", "count": randi_range(1, 2) }) # 2. 必掉史诗升阶材料:龙爪 (71129) drops.append({ "vnum": 71129, "name": "龙爪", "count": randi_range(1, 2) }) # 3. 必掉水龙专属宝箱 (50186) drops.append({ "vnum": 50186, "name": "贝兰-塞陶宝箱", "count": 1 }) # 4. 必掉灵魂之石 (50513) drops.append({ "vnum": 50513, "name": "灵魂之石", "count": 1 }) # 5. 大额金币掉落 drops.append({ "vnum": 1, "name": "金币", "count": randi_range(150000, 300000) }) return drops