Complete remaining client gap features
This commit is contained in:
+79
-9
@@ -16,6 +16,9 @@
|
||||
extends Node
|
||||
|
||||
signal target_changed(vid: int)
|
||||
# game.py SetPCTargetBoard :804 —— 按住 LCONTROL 点同阵营他人 PC 时请求开悄悄话对话框
|
||||
# (参考端 self.interface.OpenWhisperDialog(name))。game_scene 接到 chat.start_whisper()。
|
||||
signal whisper_requested(name: String)
|
||||
# OnCannotAttack / OnCannotShot / OnCannotUseSkill 的字符串码(game.py 同名回调),
|
||||
# 供 HUD 弹 localeInfo 文案。§3.4
|
||||
signal cannot_act(code: String)
|
||||
@@ -61,6 +64,8 @@ const CM := 100.0 # 米 -> 厘米
|
||||
|
||||
# §5.4 —— PVP / PK / 决斗可攻击判据(CInstanceBase::IsAttackableInstance 1:1,逐行)。
|
||||
const EntityRules = preload("res://entity_rules.gd")
|
||||
# §5.4 / §8.8 —— RecvTargetPacket 的目标框收包分派(判定树 + CanViewTargetHP)1:1。
|
||||
const TargetBoard = preload("res://target_board.gd")
|
||||
# §3.2 上行节流表(对齐 `PythonPlayerEventHandler.cpp` 的 6 个回调):
|
||||
# OnMove —— 首次开走 / 改向:立即发 FUNC_MOVE,并重置 moving/waiting 两个窗口
|
||||
# OnMoving —— 移动中周期上行:300 ms 节流,发 FUNC_MOVE
|
||||
@@ -162,6 +167,12 @@ const NAME_COMBO_ATTACK_1 := 14
|
||||
|
||||
var _target_vid := 0
|
||||
var _main_vid := 0
|
||||
# game-option「看他国玩家目标框」(constinfo VIEW_OTHER_EMPIRE_PLAYER_TARGET_BOARD,默认 1)。
|
||||
# 关掉时 TargetBoard.Open 前置过滤:异阵营 PC 目标框直接不开(uitarget.py:189-193)。
|
||||
var _view_other_empire_target := true
|
||||
# game.py SetPCTargetBoard :807 —— app.IsPressed(app.DIK_LCONTROL)。poc 侧由 game_scene
|
||||
# 的 KEY_CTRL 按下 / 松开喂 set_lcontrol_down(),点 PC 时轮询(对齐参考端 IsPressed 语义)。
|
||||
var _lcontrol_down := false
|
||||
var _last_sent_pos := Vector3.ZERO # 上一次上行时的玩家世界坐标
|
||||
var _last_moving_sent_t := 0.0 # 上一次 OnMoving 上行时刻(秒)
|
||||
var _last_waiting_sent_t := 0.0 # 上一次 OnWaiting 上行时刻(秒)
|
||||
@@ -502,13 +513,22 @@ func _heading_deg(yaw_rad: float) -> float:
|
||||
func _player_yaw() -> float:
|
||||
return pc.player.rotation.y if pc.player else 0.0
|
||||
|
||||
# CHRTYPE 分类:0 PC / 1 NPC / 2 MONSTER / 3 STONE / 4 WARP。
|
||||
# CHRTYPE 分类:0 PC / 1 NPC / 2 MONSTER / 3 STONE / 4 WARP / 5 BUILDING /
|
||||
# 6 WOODEN_DOOR。门类型既可由实体 fixture 的 building / kind 给出,也可由
|
||||
# mob_proto 的 bType=4 + 13000 / 30111..30119 race 识别。
|
||||
# 本 fork 的 GC_CHARACTER_ADD.bType 对 NPC/怪都是 0,按 race 查 mob_proto 补。
|
||||
func _entity_kind(e: Dictionary) -> int:
|
||||
if bool(e.get("building", false)):
|
||||
return EntityRules.KIND_BUILDING
|
||||
var explicit_kind := int(e.get("kind", -1))
|
||||
if explicit_kind >= EntityRules.KIND_BUILDING:
|
||||
return explicit_kind
|
||||
var ct := int(e.get("ch_type", 0))
|
||||
if ct != 0:
|
||||
return ct
|
||||
var race := int(e.get("race", 0))
|
||||
if EntityRules._is_wooden_door(e):
|
||||
return EntityRules.KIND_WOODEN_DOOR
|
||||
if race >= 1 and proto and proto.has_method("mob"):
|
||||
var m: Dictionary = proto.mob(race)
|
||||
if not m.is_empty():
|
||||
@@ -518,6 +538,8 @@ func _entity_kind(e: Dictionary) -> int:
|
||||
1: return 1
|
||||
2: return 3
|
||||
3: return 4
|
||||
4: return EntityRules.KIND_WOODEN_DOOR \
|
||||
if EntityRules._is_wooden_door(e) else EntityRules.KIND_BUILDING
|
||||
return 0
|
||||
|
||||
# 实体显示名:玩家 / NPC 走 GC_CHAR_ADD_INFO 的 name;怪没有名字包 -> 查 mob_proto。
|
||||
@@ -697,16 +719,64 @@ func _on_pick(node: Node3D) -> void:
|
||||
return
|
||||
_attack_cd = 0.0
|
||||
_change_target_to_picked_instance(vid)
|
||||
# game.py SetPCTargetBoard :804 —— 点到 PC 时 targetBoard.Open 之后,若按住 LCONTROL
|
||||
# 且同阵营(:809 IsSameEmpire)且非本人(:812 IsMainCharacterIndex)且非 building
|
||||
# (:814 INSTANCE_TYPE_BUILDING)→ interface.OpenWhisperDialog(name)。C++ 侧只对 PC
|
||||
# 分派 SetPCTargetBoard,故 poc 也只在 KIND_PC 分支查。建筑 / 木门由实体分类链识别,
|
||||
# 不满足 PC 分支时不会误触发悄悄话。
|
||||
if _entity_kind(e) == EntityRules.KIND_PC:
|
||||
var same_empire := EntityRules._is_same_empire(_main_entity(), e)
|
||||
if TargetBoard.whisper_on_ctrl_click(_lcontrol_down, same_empire, vid == _main_vid, false):
|
||||
var nm := _entity_name(e)
|
||||
if nm != "":
|
||||
whisper_requested.emit(nm)
|
||||
|
||||
# poc 版 RecvTargetPacket(PythonNetworkStreamPhaseGame.cpp:2424):C++ 侧从 EntityStore
|
||||
# 抽出 (vid, hp%),这里照参考端的判定树分派目标框——目标实例缺失 -> 关框;已死透 -> 不动框;
|
||||
# PC / building 目标 -> 只在框上是别的 VID 时关掉(不显血条);石头 / 敌对怪等「可看血」
|
||||
# 目标 -> SetHPTargetBoard;NPC / warp 等不可看血目标 -> 关框。经 target_board.gd 纯静态镜像。
|
||||
func _on_target_info(vid: int, hp_pct: int) -> void:
|
||||
if vid == 0:
|
||||
_clear_target()
|
||||
return
|
||||
_target_vid = vid
|
||||
if hud and hud.has_method("set_target"):
|
||||
var e: Dictionary = client.get_entity(vid)
|
||||
var nm := _entity_name(e) if not e.is_empty() else ""
|
||||
hud.set_target(nm if nm != "" else "目标", hp_pct)
|
||||
var e: Dictionary = client.get_entity(vid) if vid != 0 else {}
|
||||
var exists := vid != 0 and not e.is_empty()
|
||||
var dead := exists and bool(e.get("dead", false))
|
||||
var kind := _entity_kind(e) if exists else -1
|
||||
var is_pc := kind == EntityRules.KIND_PC
|
||||
var is_building := EntityRules._is_building(e)
|
||||
# uitarget.py:189-193 前置过滤:game-option 关「看他国目标框」时异阵营目标不开框。
|
||||
# empire 0 的怪/NPC/石头在 _is_same_empire 里算同阵营 → 不受影响,只挡真·他国 PC。
|
||||
if exists:
|
||||
var same_empire := EntityRules._is_same_empire(_main_entity(), e)
|
||||
if TargetBoard.hidden_as_other_empire(_view_other_empire_target, same_empire):
|
||||
_clear_target()
|
||||
return
|
||||
var can_view := TargetBoard.can_view_target_hp(
|
||||
kind == EntityRules.KIND_STONE, EntityRules._is_wooden_door(e),
|
||||
kind == EntityRules.KIND_MONSTER)
|
||||
match TargetBoard.classify(exists, dead, is_pc, is_building, can_view):
|
||||
TargetBoard.Action.CLOSE:
|
||||
_clear_target()
|
||||
TargetBoard.Action.CLOSE_IF_DIFFERENT:
|
||||
if TargetBoard.should_close_if_different(vid, _target_vid):
|
||||
_clear_target()
|
||||
TargetBoard.Action.SET_HP:
|
||||
if TargetBoard.needs_reset(vid, _target_vid):
|
||||
_target_vid = vid
|
||||
target_changed.emit(vid)
|
||||
if hud and hud.has_method("set_target"):
|
||||
var nm := _entity_name(e)
|
||||
hud.set_target(nm if nm != "" else "目标",
|
||||
TargetBoard.clamp_hp_pct(hp_pct))
|
||||
TargetBoard.Action.NONE:
|
||||
pass
|
||||
|
||||
# game_option_ui 的「看他国玩家目标框」radio(display_option_changed "target_board")。
|
||||
# uigameoption.py → constInfo.SET_VIEW_OTHER_EMPIRE_PLAYER_TARGET_BOARD(index)。
|
||||
func set_view_other_empire_target(on: bool) -> void:
|
||||
_view_other_empire_target = on
|
||||
|
||||
# game_scene 的 KEY_CTRL 按下 / 松开 → app.IsPressed(app.DIK_LCONTROL) 语义(game.py:807)。
|
||||
func set_lcontrol_down(down: bool) -> void:
|
||||
_lcontrol_down = down
|
||||
|
||||
func _clear_target() -> void:
|
||||
if _target_vid == 0:
|
||||
|
||||
Reference in New Issue
Block a user