# mob_combat_reaction_system.gd —— 怪物主动仇恨视野、追击脱战与连击击退硬直(40250 官方 1:1 对齐) # 对齐源码: # - 40250 server/game/src/char_state.cpp:250-380 (StateBattle, StateIdle, 追击与脱战) # - 40250 server/game/src/battle.cpp:110-180 (battle_hit, 攻击判定与受击推力) # - 40250 ClientVS22/source/UserInterface/ActorInstanceBattle.cpp (__HitGood, __HitGreate) class_name MobCombatReactionSystem extends RefCounted const DEFAULT_AGGRO_RADIUS := 18.0 # 主动怪索敌视野半径 (18 米) const MAX_LEASH_DISTANCE := 40.0 # 最大追击拉脱距离 (40 米) const KNOCKBACK_FORCE_M := 1.5 # 四连击击退推力距离 (1.5 米) enum MobAIState { IDLE, # 巡逻/游荡 CHASE, # 仇恨追击玩家 RETREAT, # 超过拉脱距离,放弃仇恨返回出生点 } ## 检查是否进入主动怪仇恨视野 static func check_aggro(mob_pos: Vector3, player_pos: Vector3, is_aggressive := true, aggro_radius := DEFAULT_AGGRO_RADIUS) -> bool: if not is_aggressive: return false var dist := mob_pos.distance_to(player_pos) return dist <= aggro_radius ## 检查是否超出追击拉脱最大距离 static func check_leash_exceeded(mob_pos: Vector3, spawn_pos: Vector3, max_leash := MAX_LEASH_DISTANCE) -> bool: var dist := mob_pos.distance_to(spawn_pos) return dist > max_leash ## 执行拉脱脱战重置 (40250 char_state.cpp 怪物脱战回位并回满生命值) static func perform_leash_reset(mob_data: Dictionary, spawn_pos: Vector3) -> Dictionary: var max_hp := int(mob_data.get("max_hp", 1000)) mob_data["hp"] = max_hp mob_data["target_vid"] = 0 mob_data["state"] = MobAIState.RETREAT return { "leashed": true, "reset_hp": max_hp, "return_pos": spawn_pos, "msg": "怪物超出追击范围,脱离战斗并回满生命值返回出生点!" } ## 计算普通连击与受击反应 (40250 battle.cpp: 第1-2击普通受击,第3-4击击退击倒) ## combo_step: 1..4 当前连击段数 ## attack_heading_rad: 攻击朝向弧度 (用于计算受力击退向量) static func calculate_combo_reaction(combo_step: int, mob_pos: Vector3, attack_heading_rad: float) -> Dictionary: var normalized_step := ((combo_step - 1) % 4) + 1 if normalized_step in [1, 2]: # 前两击:普通受击硬直 (HitReaction.good) return { "reaction_type": "DAMAGE_STUN", "is_knockback": false, "push_offset": Vector3.ZERO, "anim": "damage", "stun_duration": 0.2, # 0.2 秒受击硬直 } else: # 第三、四击:强力击退并击倒 (HitReaction.greate) # 顺着攻击朝向将怪物向后击退 1.5 米 var push_dir := Vector3(sin(attack_heading_rad), 0, cos(attack_heading_rad)).normalized() var push_vec := push_dir * KNOCKBACK_FORCE_M var new_pos := mob_pos + push_vec return { "reaction_type": "KNOCKBACK_FLYING", "is_knockback": true, "push_offset": push_vec, "target_pos": new_pos, "anim": "knockdown", "standup_anim": "standup", "knockdown_duration": 0.8, # 倒地至起身耗时 }