- 桥梁与静态物体高度采样修复: - 严格对齐 40250 CMapOutdoor::GetHeight 与 CAttributeInstance::GetHeight - 解析 .mdatr 中的 AttributeHeight 网格,使用 is_in_triangle_2d 准确计算桥面多边形平面方程 - sample_height 查询邻近区块并返回 fMAX(fObjectHeight, fTerrainHeight),彻底解决走上桥面穿透掉入水底/河床的问题 - 新增 test_bridge_height_parity.gd 自动化对拍测试 - 40250 怪物击杀经验动效: - 1:1 实现 FLY_EXP(0) / FLY_HP / FLY_SP 粒子轨迹与爆炸吸附 - 40250 客户端全系统功能对齐(Batches 1-31): - 包含公会、交易、骑乘、变身、钓鱼、采矿、商城、信件、结婚、地牢等 134 套对拍系统与自动化回归测试 - 文档沉淀: - 新增 docs/CLIENT-PARITY-AUDIT-AND-FIX-GUIDE.md 客户端对拍缺陷发现与修复工程指南
73 lines
3.0 KiB
GDScript
73 lines
3.0 KiB
GDScript
# 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, # 倒地至起身耗时
|
|
}
|