fix: 装备属性面板避让逻辑 + 多项功能更新

- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧
- inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域
- 包含其他累积的功能开发和测试文件
This commit is contained in:
shen
2026-09-21 16:38:59 -07:00
parent 1522a8a1a1
commit c93894313a
5498 changed files with 4558004 additions and 1442 deletions
+51
View File
@@ -49,6 +49,14 @@ const KIND_WARP := 4
const KIND_BUILDING := 5
const KIND_WOODEN_DOOR := 6
# CInstanceBase::CanPickInstance / InstanceBase.h affect ordinals.
# EntityStore carries the two affect words as one uint64 bitset. Tests and
# older adapters may also provide the decoded booleans/array; the helper below
# accepts both shapes so the target gate has one authoritative implementation.
const AFFECT_INVISIBILITY := 1
const AFFECT_EUNHYEONG := 18
const AFFECT_REVIVE_INVISIBILITY := 27
# --- alignment(善恶)---------------------------------------------------------
# CInstanceBase::GetAlignmentGradeInstanceBase.cpp:502
@@ -111,6 +119,49 @@ static func _is_building(e: Dictionary) -> bool:
return bool(e.get("building", false)) or _kind(e) == KIND_BUILDING \
or _kind(e) == KIND_WOODEN_DOOR
static func _has_affect(e: Dictionary, affect_type: int) -> bool:
if bool(e.get("invisibility", false)) and affect_type == AFFECT_INVISIBILITY:
return true
if bool(e.get("eunhyeong", false)) and affect_type == AFFECT_EUNHYEONG:
return true
if bool(e.get("revive_invisibility", false)) and affect_type == AFFECT_REVIVE_INVISIBILITY:
return true
var flags := int(e.get("affect_flags", 0))
if affect_type < 64 and (flags & (1 << affect_type)) != 0:
return true
var affects: Variant = e.get("affects", [])
if affects is Array:
for a in affects:
if a is Dictionary and int(a.get("type", -1)) == affect_type:
return true
return false
static func can_pick_instance(e: Dictionary, ctx: Dictionary = {}) -> bool:
# CInstanceBase::__IsInViewFrustum. The native entity layer normally only
# exposes actors after this check; explicit false is retained for UI/script
# selection and headless replay fixtures.
if e.has("in_view_frustum") and not bool(e.get("in_view_frustum", true)):
return false
if e.has("can_pick") and not bool(e.get("can_pick", true)):
return false
# Door corpses are rejected by the dedicated door branch, then all dead
# instances are rejected by the common IsDead() branch.
if _is_building(e) and _kind(e) == KIND_WOODEN_DOOR and bool(e.get("dead", false)):
return false
if bool(e.get("dead", false)):
return false
if _is_pc(e):
# __MainCanSeeHiddenThing() in this 40250 build returns false, so
# EUNHYEONG is not pickable. The other two invisibility affects are
# unconditional gates as in InstanceBase.cpp:2275-2284.
if _has_affect(e, AFFECT_EUNHYEONG) and not bool(ctx.get("can_see_hidden", false)):
return false
if _has_affect(e, AFFECT_REVIVE_INVISIBILITY) or _has_affect(e, AFFECT_INVISIBILITY):
return false
return true
# --- killer / party / empire / duel / pvp -----------------------------------
static func _is_killer(e: Dictionary) -> bool: