fix(combat): 战斗逐项对齐 40250,修复移动 / 技能释放与武器挂点
- 连击类型由 combo_changed 驱动(SetComboSkillFlag,技能 122 等级) - 命中判定改为 .msa 刀尖 Z 圆柱 vs .msm 防御球(hit_collision.gd 逐行移植) - _register_hit 改为 map::insert 语义,修正命中上限 - 攻速同时缩放 GetAttackingElapsedTime 与攻击动作速率;按武器动作模式目录绑定攻击段 - 去掉本地连击超时,motion_bound 清命中表 / 连击段号 - __ProcessDataAttackSuccess:InsertDelay 硬直、physics_push.gd 击退 + GetBlendingPosition 同步、 命中特效、__HitGood / __HitGreate / __HitStone 受击动作链与抖动(ui/hit_reaction.gd) - ClassicSession::send_use_skill 不再夹带 CG_FLY_TARGETING - mac 前进 / 后退方向与技能释放修复;武器按职业骨骼挂到手上 - 新增 hit_collision / physics_push / hit_view / net_world_push / weapon_attach 测试; gpu_pose_bounds / race_motion_assembly 适配 damage 随机变体 - 文档:CLIENT-GAP.md、CLIENT-GAP-FIX.md §3.5 / §3.7 与 C.5 增量 130 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ft3kXpNdLbKEfg5uDLfqVF
This commit is contained in:
+42
-12
@@ -5,8 +5,10 @@
|
||||
# em.setup(m2client, item_list, model_getter, assets_root, race)
|
||||
#
|
||||
# 监听 M2Client.inventory_changed(window == EQUIPMENT),读 get_equipment():
|
||||
# WEAR_WEAPON(4) -> model.weapon_gr2 = item_list.model(vnum) 解析后的真实路径
|
||||
# WEAR_SHIELD(10)-> model.shield_gr2(左手刚体挂点,同 weapon)
|
||||
# WEAR_WEAPON(4) -> item_list.model(vnum) 解析后的真实路径,按左右手分给
|
||||
# model.weapon_gr2(PART_WEAPON)/ model.shield_gr2(PART_WEAPON_LEFT)
|
||||
# (ActorInstanceAttach.cpp AttachWeapon:匕首双手、弓左手、骑马的扇双手)
|
||||
# WEAR_SHIELD(10)-> 不渲染(参考端没有盾牌挂件,item_list 的盾也没有模型)
|
||||
# WEAR_HEAD(1) -> 有模型的头盔 = 覆盖发型槽(Metin2 约定:头防替换头发)
|
||||
# WEAR_BODY(0) -> race_spec.shape(armor_shape_of(vnum)) -> model.gr2_path (+ 换肤)
|
||||
# armor_model_map[vnum] 若给了则优先
|
||||
@@ -34,6 +36,12 @@ const PART_WEAPON := 1
|
||||
const PART_HEAD := 2
|
||||
const PART_HAIR := 3
|
||||
const CHR_EQUIPPART_HAIR := 3 # 兼容旧引用
|
||||
# item_length.h EWeaponSubTypes(CItemData::GetWeaponType = bSubType)
|
||||
const WEAPON_SUB_DAGGER := 1
|
||||
const WEAPON_SUB_BOW := 2
|
||||
const WEAPON_SUB_FAN := 5
|
||||
const HAND_RIGHT := 1
|
||||
const HAND_LEFT := 2
|
||||
const CLASS_OF := ["warrior", "assassin", "sura", "shaman"]
|
||||
|
||||
var client: Node
|
||||
@@ -47,7 +55,7 @@ var _spec_tried := false
|
||||
var _last_weapon_vnum := -1
|
||||
var _last_body_vnum := -1
|
||||
var _last_head_vnum := -2 # -1 是「发型被遮挡」的有效态,用 -2 当「未应用」哨兵
|
||||
var _last_shield_vnum := -1
|
||||
var _last_weapon_hands := -1
|
||||
var _last_hair_part := -1
|
||||
var main_getter: Callable = Callable() # func() -> int:主角 vid(取 parts 用)
|
||||
var _remote_mode := false
|
||||
@@ -77,6 +85,11 @@ func setup(m2client: Node, il: RefCounted, model_getter: Callable, assets := "",
|
||||
client.entity_info.connect(func(v, _d):
|
||||
if main_getter.is_valid() and int(main_getter.call()) == v:
|
||||
refresh())
|
||||
# 上 / 下马改变扇子的左右手(__IsLeftHandWeapon: FAN && IsMountingHorse)
|
||||
if client and client.has_signal("mount_changed"):
|
||||
client.mount_changed.connect(func(v):
|
||||
if main_getter.is_valid() and int(main_getter.call()) == v:
|
||||
refresh())
|
||||
|
||||
# 远端 PC 不读取本地 get_equipment();参考端直接消费
|
||||
# GC_CHAR_ADDITIONAL_INFO / GC_CHARACTER_UPDATE 的 awPart[4]。
|
||||
@@ -139,17 +152,34 @@ func refresh() -> void:
|
||||
# --- 武器:parts[WEAPON] 优先,为 0 回退 WEAR_WEAPON;过 PartHiding 遮挡 ---------
|
||||
var wpn_vnum := _eff(parts, PART_WEAPON, eq, WEAR_WEAPON)
|
||||
var wpn_eff := PartHiding.effective_weapon(wpn_vnum, raw_shape, is_poly)
|
||||
if wpn_eff != _last_weapon_vnum:
|
||||
var hands := _weapon_hands(wpn_eff)
|
||||
if wpn_eff != _last_weapon_vnum or hands != _last_weapon_hands:
|
||||
_last_weapon_vnum = wpn_eff
|
||||
model.set("weapon_gr2", _resolve_weapon(wpn_eff))
|
||||
_last_weapon_hands = hands
|
||||
# 左手用 GetSubModelThing():item .msm 加载在参考端被注释掉,恒为同一个 gr2
|
||||
var wpath := _resolve_weapon(wpn_eff)
|
||||
model.set("weapon_gr2", wpath if hands & HAND_RIGHT else "")
|
||||
model.set("shield_gr2", wpath if hands & HAND_LEFT else "")
|
||||
|
||||
# --- 盾(左手挂点,同武器遮挡规则)--------------------------------------------
|
||||
if eq.size() > WEAR_SHIELD:
|
||||
var sh_vnum := int(eq[WEAR_SHIELD].get("vnum", 0))
|
||||
var sh_eff := 0 if PartHiding.weapon_hidden(raw_shape, is_poly, sh_vnum) else sh_vnum
|
||||
if sh_eff != _last_shield_vnum:
|
||||
_last_shield_vnum = sh_eff
|
||||
model.set("shield_gr2", _resolve_weapon(sh_eff))
|
||||
# ActorInstanceAttach.cpp __IsRightHandWeapon / __IsLeftHandWeapon -> HAND_* 位掩码
|
||||
func _weapon_hands(vnum: int) -> int:
|
||||
if vnum == 0:
|
||||
return 0
|
||||
var sub := -1
|
||||
if proto and proto.has_method("item"):
|
||||
sub = int(proto.item(vnum).get("sub_type", -1))
|
||||
if sub == WEAPON_SUB_DAGGER or (sub == WEAPON_SUB_FAN and _is_mounting()):
|
||||
return HAND_RIGHT | HAND_LEFT
|
||||
if sub == WEAPON_SUB_BOW:
|
||||
return HAND_LEFT
|
||||
return HAND_RIGHT
|
||||
|
||||
# IsMountingHorse:主角实体 mount_vnum 非 0。远端 PC 暂无坐骑状态输入(seam)。
|
||||
func _is_mounting() -> bool:
|
||||
if _remote_mode or not main_getter.is_valid() or client == null or not client.has_method("get_entity"):
|
||||
return false
|
||||
var vid: int = main_getter.call()
|
||||
return vid != 0 and int(client.get_entity(vid).get("mount_vnum", 0)) != 0
|
||||
|
||||
# §4.1 修改 4 seam:40250 实体表暂无变身字段(m2_client.cpp entity dict 无 poly_race /
|
||||
# polymorph)。一旦 GC_CHARACTER_UPDATE / GC_CHAR_ADD_INFO 带上变身 race,这里改成读
|
||||
|
||||
Reference in New Issue
Block a user