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
+57 -33
View File
@@ -84,6 +84,61 @@ static void combat_data(const Node& root, Msa& out) {
}
}
static void motion_event(const Node& ev, MotionEvent& e) {
e.type = ev.inum("MotionEventType");
e.start_time = ev.num("StartingTime");
e.duration_time = ev.num("DuringTime");
e.effect_file = ev.str("EffectFileName");
e.sound_file = ev.str("SoundFileName");
e.attaching_bone = ev.str("AttachingBoneName");
e.attaching = ev.inum("AttachingEnable") != 0;
e.following = ev.inum("FollowingEnable") != 0;
e.independent = ev.inum("IndependentFlag") != 0;
e.fishing_effect = ev.inum("FishingEffectFlag") != 0;
vec3(ev.find("EffectPosition"), e.position);
// 40250 TMotionEventDataFly has its own resource and offset fields.
e.fly_file = ev.str("FlyFileName");
e.fly_attaching_bone = ev.str("AttachingBoneName");
e.fly_attaching = ev.inum("AttachingEnable") != 0;
vec3(ev.find("FlyPosition"), e.fly_position);
// 40250 TScreenWavingEventData defaults AffectingRange to zero and reads
// DuringTime/Power from the event itself.
e.power = ev.inum("Power");
e.affecting_range = ev.inum("AffectingRange");
// 40250 TMotionAttackingEventData defaults EnableHitProcess to TRUE.
e.enable_hit_process = ev.inum("EnableHitProcess", 1) != 0;
e.attack_type = ev.inum("AttackType", ev.inum("AttackingType"));
e.hitting_type = ev.inum("HittingType");
e.stiffen_time = ev.num("StiffenTime");
e.invisible_time = ev.num("InvisibleTime");
e.external_force = ev.num("ExternalForce");
e.hit_limit_count = ev.inum("HitLimitCount");
e.collision_type = ev.inum("CollisionType");
for (const Node& g : ev.groups) {
if (g.name.size() < 10 || g.name.compare(0, 10, "SphereData") != 0)
continue;
MotionEvent::CollisionSphere sphere;
sphere.radius = g.num("Radius");
vec3(g.find("Position"), sphere.position);
e.collision_spheres.push_back(sphere);
}
}
static void motion_events(const Node& root, Msa& out) {
const Node* med = root.group("MotionEventData");
if (!med) return;
int count = med->inum("MotionEventDataCount", int(med->groups.size()));
(void)count;
for (const Node& ev : med->groups) {
MotionEvent e;
motion_event(ev, e);
out.events.push_back(std::move(e));
}
}
bool parse_msa(const std::string& text, Msa& out, std::string* err) {
Node root;
if (!parse_textscript(text, root, err)) return false;
@@ -95,24 +150,7 @@ bool parse_msa(const std::string& text, Msa& out, std::string* err) {
loop_data(root, out);
combat_data(root, out);
if (const Node* med = root.group("MotionEventData")) {
int count = med->inum("MotionEventDataCount", int(med->groups.size()));
(void)count;
for (const Node& ev : med->groups) {
MotionEvent e;
e.type = ev.inum("MotionEventType");
e.start_time = ev.num("StartingTime");
e.effect_file = ev.str("EffectFileName");
e.sound_file = ev.str("SoundFileName");
e.attaching_bone = ev.str("AttachingBoneName");
e.attaching = ev.inum("AttachingEnable") != 0;
e.following = ev.inum("FollowingEnable") != 0;
e.independent = ev.inum("IndependentFlag") != 0;
e.fishing_effect = ev.inum("FishingEffectFlag") != 0;
vec3(ev.find("EffectPosition"), e.position);
out.events.push_back(std::move(e));
}
}
motion_events(root, out);
if (out.motion_gr2.empty()) { if (err) *err = "msa: 缺 MotionFileName"; return false; }
return true;
@@ -128,21 +166,7 @@ bool parse_msa_file(const std::string& path, Msa& out, std::string* err) {
vec3(root.find("Accumulation"), out.accumulation);
loop_data(root, out);
combat_data(root, out);
if (const Node* med = root.group("MotionEventData"))
for (const Node& ev : med->groups) {
MotionEvent e;
e.type = ev.inum("MotionEventType");
e.start_time = ev.num("StartingTime");
e.effect_file = ev.str("EffectFileName");
e.sound_file = ev.str("SoundFileName");
e.attaching_bone = ev.str("AttachingBoneName");
e.attaching = ev.inum("AttachingEnable") != 0;
e.following = ev.inum("FollowingEnable") != 0;
e.independent = ev.inum("IndependentFlag") != 0;
e.fishing_effect = ev.inum("FishingEffectFlag") != 0;
vec3(ev.find("EffectPosition"), e.position);
out.events.push_back(std::move(e));
}
motion_events(root, out);
if (out.motion_gr2.empty()) { if (err) *err = "msa: 缺 MotionFileName (" + path + ")"; return false; }
return true;
}