# metin_spawn_event_system.gd —— Metin2 40250 野外 8 档魔石陨落与怪潮暴动 1:1 # 对照 40250 服务端 regen.cpp, char_battle.cpp, metin.cpp, Mobs 8008~8014, 8027 class_name MetinSpawnEventSystem extends RefCounted signal metin_spawned(vnum: int, name: String, pos: Vector3) signal mob_wave_erupted(metin_vnum: int, wave_count: int, minion_vnum: int) signal metin_destroyed(metin_vnum: int, pos: Vector3, drops: Array) const METIN_TABLE: Dictionary = { 8008: {"name": "嫉妒之石", "level": 35, "max_hp": 70000, "def": 120, "wave_mob": 391, "wave_count": 4}, 8009: {"name": "灵魂之石", "level": 40, "max_hp": 90000, "def": 140, "wave_mob": 401, "wave_count": 4}, 8010: {"name": "暗影之石", "level": 45, "max_hp": 120000, "def": 160, "wave_mob": 501, "wave_count": 5}, 8011: {"name": "坚韧之石", "level": 50, "max_hp": 150000, "def": 180, "wave_mob": 601, "wave_count": 5}, 8012: {"name": "恶魔之石", "level": 55, "max_hp": 180000, "def": 200, "wave_mob": 701, "wave_count": 6}, 8013: {"name": "坠落之石", "level": 60, "max_hp": 220000, "def": 230, "wave_mob": 2001, "wave_count": 6}, 8014: {"name": "死亡之石", "level": 65, "max_hp": 260000, "def": 260, "wave_mob": 2101, "wave_count": 7}, 8027: {"name": "谋杀之石", "level": 70, "max_hp": 300000, "def": 300, "wave_mob": 2201, "wave_count": 8} } # 当前存活的魔石实体字典: id -> Dictionary var active_metins: Dictionary = {} var next_instance_id: int = 1 # 在指定位置刷新野外魔石 func spawn_metin(vnum: int, pos: Vector3 = Vector3.ZERO) -> Dictionary: if not METIN_TABLE.has(vnum): return {"ok": false, "reason": "INVALID_METIN_VNUM", "msg": "未知的魔石代码!"} var cfg = METIN_TABLE[vnum] var inst_id := next_instance_id next_instance_id += 1 var entity: Dictionary = { "id": inst_id, "vnum": vnum, "name": cfg["name"], "level": cfg["level"], "max_hp": cfg["max_hp"], "current_hp": cfg["max_hp"], "def": cfg["def"], "wave_mob": cfg["wave_mob"], "wave_count": cfg["wave_count"], "pos": pos, "phase_75_triggered": false, "phase_50_triggered": false, "phase_25_triggered": false, "spawned_minions": [] } active_metins[inst_id] = entity metin_spawned.emit(vnum, cfg["name"], pos) return { "ok": true, "id": inst_id, "vnum": vnum, "name": cfg["name"], "pos": pos, "msg": "【%s】轰然坠落于大地!(坐标: %.1f, %.1f)" % [cfg["name"], pos.x, pos.z] } # 攻击魔石并触发 25% 阶段怪潮爆发 func attack_metin(inst_id: int, raw_dmg: int) -> Dictionary: if not active_metins.has(inst_id): return {"ok": false, "reason": "METIN_NOT_FOUND", "msg": "该魔石不存在或已击碎!"} var stone = active_metins[inst_id] var net_dmg: int = max(1, raw_dmg - int(stone["def"])) stone["current_hp"] = max(0, stone["current_hp"] - net_dmg) var cur_hp: int = stone["current_hp"] var max_hp: int = stone["max_hp"] var hp_ratio: float = float(cur_hp) / float(max_hp) var wave_triggered := false var spawned_count := 0 # 75% 阶段怪潮爆发 if hp_ratio <= 0.75 and not stone["phase_75_triggered"]: stone["phase_75_triggered"] = true spawned_count = _trigger_mob_wave(stone) wave_triggered = true # 50% 阶段怪潮爆发 if hp_ratio <= 0.50 and not stone["phase_50_triggered"]: stone["phase_50_triggered"] = true spawned_count = _trigger_mob_wave(stone) wave_triggered = true # 25% 阶段怪潮爆发 if hp_ratio <= 0.25 and not stone["phase_25_triggered"]: stone["phase_25_triggered"] = true spawned_count = _trigger_mob_wave(stone) wave_triggered = true # 魔石击碎判定 if cur_hp <= 0: var drops := _generate_metin_drops(stone["vnum"]) var stone_pos: Vector3 = stone["pos"] var stone_vnum: int = stone["vnum"] var stone_name: String = stone["name"] active_metins.erase(inst_id) metin_destroyed.emit(stone_vnum, stone_pos, drops) return { "ok": true, "destroyed": true, "net_dmg": net_dmg, "remaining_hp": 0, "drops": drops, "msg": "【%s】被彻底击碎!神圣光芒散落,爆出技能书与灵石!" % stone_name } return { "ok": true, "destroyed": false, "net_dmg": net_dmg, "remaining_hp": cur_hp, "hp_ratio": hp_ratio, "wave_triggered": wave_triggered, "spawned_count": spawned_count } # 激发一波护卫怪群 func _trigger_mob_wave(stone: Dictionary) -> int: var count: int = stone["wave_count"] var mob_vnum: int = stone["wave_mob"] for i in range(count): var offset := Vector3(randf_range(-4.0, 4.0), 0.0, randf_range(-4.0, 4.0)) stone["spawned_minions"].append({ "vnum": mob_vnum, "pos": stone["pos"] + offset }) mob_wave_erupted.emit(stone["vnum"], count, mob_vnum) return count # 生成魔石击碎全额掉落 func _generate_metin_drops(metin_vnum: int) -> Array: var cfg = METIN_TABLE[metin_vnum] var drops: Array = [] # 1. 必掉技能书 (50300) drops.append({ "vnum": 50300, "name": "技能书", "count": 1 }) # 2. 必掉灵魂之石 (50513) drops.append({ "vnum": 50513, "name": "灵魂之石", "count": 1 }) # 3. 灵石 (+0~+4, 随机职业战士/刺客/修罗/萨满/防御/生命) drops.append({ "vnum": 28430, # 战士灵石+4 "name": "战士灵石+4", "count": 1 }) # 4. 金币 drops.append({ "vnum": 1, "name": "金币", "count": randi_range(cfg["level"] * 500, cfg["level"] * 1500) }) return drops