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
+62
View File
@@ -22,6 +22,12 @@ extends RefCounted
var _by_id := {}
var count := 0
# PythonSkill.h: SKILL_EFFECT_COUNT / SKILL_GRADEGAP;当前 assets/root/constinfo.py
# 的 USE_SKILL_EFFECT_UPGRADE_ENABLE=1,故本地与远端动作都必须保留等级偏移。
const SKILL_EFFECT_COUNT := 4
const SKILL_GRADEGAP := 25
var skill_effect_upgrade_enabled := true
const JOB_DIR := {
"WARRIOR": "warrior",
"ASSASSIN": "assassin",
@@ -228,15 +234,46 @@ func name_of(id: int) -> String:
func motion_idx_of(id: int) -> int:
return int(_by_id.get(id, {}).get("motion_idx", 0))
func set_skill_effect_upgrade_enabled(enabled: bool) -> void:
skill_effect_upgrade_enabled = enabled
# CPythonSkill::SSkillData::GetSkillMotionIndex(iGrade)。grade 超出该技能实际
# 注册的 grade 数量时回退基础 motion index,和 RegisterSkillDesc 的空槽填 base 一致。
func motion_idx_for_grade(id: int, grade: int = -1) -> int:
var base := motion_idx_of(id)
if not skill_effect_upgrade_enabled or grade < 0 or grade >= SKILL_EFFECT_COUNT:
return base
var grade_count := clampi(int(_by_id.get(id, {}).get("grades", 1)), 1, SKILL_EFFECT_COUNT)
return base + grade * SKILL_GRADEGAP if grade < grade_count else base
func motion_name_of(id: int) -> String:
return String(_by_id.get(id, {}).get("motion", ""))
func motion_name_by_idx(motion_idx: int) -> String:
# 先保留基础索引的精确匹配;没有基础项时,再解析等级偏移索引。
for id in _by_id:
if int(_by_id[id].get("motion_idx", 0)) == motion_idx:
return String(_by_id[id].get("motion", ""))
for id in _by_id:
var base := int(_by_id[id].get("motion_idx", 0))
var grade_count := clampi(int(_by_id[id].get("grades", 1)), 1, SKILL_EFFECT_COUNT)
for grade in range(1, grade_count):
if skill_effect_upgrade_enabled and base + grade * SKILL_GRADEGAP == motion_idx:
return String(_by_id[id].get("motion", ""))
return ""
func motion_grade_by_idx(motion_idx: int) -> int:
for id in _by_id:
if int(_by_id[id].get("motion_idx", 0)) == motion_idx:
return 0
for id in _by_id:
var base := int(_by_id[id].get("motion_idx", 0))
var grade_count := clampi(int(_by_id[id].get("grades", 1)), 1, SKILL_EFFECT_COUNT)
for grade in range(1, grade_count):
if skill_effect_upgrade_enabled and base + grade * SKILL_GRADEGAP == motion_idx:
return grade
return 0
func _attrs(id: int) -> String:
return String(_by_id.get(id, {}).get("attrs", ""))
@@ -281,6 +318,28 @@ func is_horse_skill(id: int) -> bool: # IsHorseSkill
func is_moving_skill(id: int) -> bool: # IsMovingSkill
return _has_attr(id, "MOVING_SKILL")
# CPythonSkill::GetMotionLoopCount(fSkillPoint): the value is calculated from
# the same efficiency percentage as cooldown/SP and packed into OnUseSkill's
# uArg low nibble by CActorInstance::__OnUseSkill.
func motion_loop_count_of(id: int, level: int) -> int:
var formula := String(_by_id.get(id, {}).get("motion_loop_count_formula", ""))
if formula == "":
return 0
var expression := Expression.new()
if expression.parse(formula, ["SkillPoint"]) != OK:
return 0
var value: Variant = expression.execute([_skill_point(level)])
if expression.has_execute_failed() or not (value is float or value is int):
return 0
return maxi(0, int(value))
# CActorInstance::__OnUseSkill: uArg = loop count | (isMovingSkill ? 1<<4 : 0).
func motion_state_arg(id: int, level: int) -> int:
var arg := motion_loop_count_of(id, level) & 0x0f
if is_moving_skill(id):
arg |= 1 << 4
return arg
func is_melee(id: int) -> bool: # IsMeleeSkill
return _has_attr(id, "MELEE_ATTACK")
@@ -437,6 +496,9 @@ func _load_msk(entry: Dictionary) -> void:
var tcf := _ascii_field(bytes, "TargetCountFormula")
if tcf != "":
entry["target_count_formula"] = tcf.trim_prefix("\"").trim_suffix("\"")
var mlcf := _ascii_field(bytes, "MotionLoopCountFormula")
if mlcf != "":
entry["motion_loop_count_formula"] = mlcf.trim_prefix("\"").trim_suffix("\"")
var trange := _ascii_field(bytes, "Range")
if trange != "":
entry["target_range"] = max(0, int(trange.trim_prefix("\"").trim_suffix("\"")))