Skip to content

update - #92

Open
wuyingwongggg wants to merge 13 commits into
Project-N-E-K-O:mainfrom
wuyingwongggg:main
Open

update#92
wuyingwongggg wants to merge 13 commits into
Project-N-E-K-O:mainfrom
wuyingwongggg:main

Conversation

@wuyingwongggg

@wuyingwongggg wuyingwongggg commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

machineHeatRecoveryeffect修复
修复了machine相关脚本数值根据当前值的变化而变化的问题,改为使用绝对值
优化RigidBodyWorldItemEntity,投掷后使其在接触airwall时停止飞行
添加briefcase投掷武器相关场景,新增briefcase生成特效逻辑
修复了dotburneffect在收到二次伤害后立刻重置burn伤害计时的错误逻辑
添加spinecotroller跳帧方法,
添加玩家攻击循环active的方法
优化cube追踪逻辑,实现360度追踪,以及根据伤害对象自动选择追踪目标
boomerang优化
新增电击核心以及相关脚本
修复cube无法找到attacker的问题
新增machinecore中heatbar在当前heat值大于maxheat值时继续等比增大的方法
优化电击核心运动逻辑
新增lightingBeam释放逻辑
新增machineB系列卡牌草图
新增machineB系列脚本效果
修改玩家攻击模板中hit 事件回合隔离防止数据污染
新增卡牌当前可选数值的高亮功能
新增B004B005构筑脚本

Summary by CodeRabbit

  • 新功能
    • 新增电击核心、多功能公文包及相关投掷玩法。
    • 新增灼烧、火焰环、热流冲击、机器超频等构筑效果。
    • 新增普通、精英及特殊敌人掉落内容。
    • 新增闪电、电弧与火焰视觉效果。
    • 构筑卡牌支持动态数值与当前等级高亮。
  • 平衡调整
    • 调整构筑数值、敌人伤害、眩晕时长及热量机制。
    • 更新关卡房间池与难度配置。
  • 界面优化
    • 优化热量显示布局、卡牌描述排版与热量溢出显示。
  • 问题修复
    • 改善投掷物碰墙、攻击连段衔接、目标检测及特效显示。

machineHeatRecoveryeffect修复
修复了machine相关脚本数值根据当前值的变化而变化的问题,改为使用绝对值
优化RigidBodyWorldItemEntity,投掷后使其在接触airwall时停止飞行
添加briefcase投掷武器相关场景,新增briefcase生成特效逻辑
修复了dotburneffect在收到二次伤害后立刻重置burn伤害计时的错误逻辑
添加spinecotroller跳帧方法,
添加玩家攻击循环active的方法
优化cube追踪逻辑,实现360度追踪,以及根据伤害对象自动选择追踪目标
boomerang优化
新增电击核心以及相关脚本
修复cube无法找到attacker的问题
新增machinecore中heatbar在当前heat值大于maxheat值时继续等比增大的方法
优化电击核心运动逻辑
新增lightingBeam释放逻辑
新增machineB系列卡牌草图
新增machineB系列脚本效果
修改玩家攻击模板中hit 事件回合隔离防止数据污染
新增卡牌当前可选数值的高亮功能
新增B004B005构筑脚本
@greptile-apps

greptile-apps Bot commented Aug 5, 2026

Copy link
Copy Markdown

Too many files changed for review (270 files, 100 file limit).

Bypass the limit by tagging @greptile-apps to review.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

本次变更更新构筑描述模板、机器热量效果、玩家攻击流程、投掷武器、战斗效果、敌人掉落、关卡配置和 Godot 视觉资源喵。

Changes

构筑与机器系统

Layer / File(s) Summary
构筑定义与动态描述
resources/builds/*, scripts/systems/*, scripts/ui/*, scenes/ui/*
构筑资源新增效果条目、图标和层级参数。构筑卡片支持动态占位符、数值格式化和当前层级高亮喵。
机器热量修饰器与效果
scripts/builds/buildcore/*, scripts/builds/machine/*, scenes/builds/machine/*
机器核心新增热量属性修饰器、冻结、热量倍率和热量溢出逻辑。新增余温、超频、热流冲击、火焰环和热量衰减效果喵。

战斗与资源

Layer / File(s) Summary
投掷武器与攻击流程
resources/items/*, scenes/weapons/*, scripts/actors/heroes/*
新增公文包和 E-Core 投掷武器。持握动画改为通用查找。攻击恢复阶段支持跳过 Warmup,并同步 Spine 动画时间喵。
通用效果与投射物
scripts/effects/*, scripts/fx/*, scripts/items/world/*, scripts/core/*
新增灼烧、公文包生成和 E-Core 攻击效果。闪电光束支持随机电弧和循环脉冲。投掷物支持 AirWall 检测。击退逻辑移至 KnockbackDriver 喵。
掉落与关卡场景
resources/loot/*, scenes/actors/characters/*, scenes/Stage_*.tscn, scenes/levels/*
新增普通、精英和特殊掉落表。敌人场景改用新掉落表。Stage 2 和 Stage 3 更新中间房间池配置喵。
场景与视觉资源
project.godot, scenes/*, shaders/*, resources/effects/*, 构筑卡牌描述模板机制.md
更新物理层名称、HUD 布局、敌人和武器场景、闪电材质、火焰着色器及效果动画资源喵。

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Poem

热量越过上限,闪电开始转圈喵
公文包打开,火墙随后出现喵
构筑卡片亮起当前层喵
连击跳过 Warmup 向前冲喵
灼烧与投掷共同登场喵

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.40% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive 标题“update”过于笼统,无法明确概括本次涵盖的热量逻辑、投掷武器、效果系统和界面等主要变更喵。 请将标题改为能概括主要变更的具体单句,例如“扩展机器热量效果并新增投掷武器与构筑系统”喵。
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4dfca9137a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

if (node is Node2D node2D)
{
// 独立加入世界层:不挂在本场景下,随本场景销毁而销毁
world.AddChild(node2D);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Apply overrides before adding spawned nodes

When BriefcaseAttack spawns CubeData, AddChild runs the cube's _Ready() before the EffectOverrides loop sets TargetableFactions = Enemy. RotatingCube._Ready() builds the attack area's collision mask from the old scene value (Player), so these spawned attack cubes aim at enemies later but never subscribe to the enemy physics layer and won't receive enemy hit signals. Apply the overrides before adding the node to the tree, or reapply the cube's mask after overriding.

Useful? React with 👍 / 👎.

_core.MaxHeat = _originalMaxHeat * CurrentCap;
_core.DecayRate = _originalDecayRate * CurrentDecay;
_core.HeatDrainRate = _originalHeatDrainRate * CurrentDecay;
_core.SetStatModifier(MachineCoreEffect.HeatStat.MoveHeatRate, EffectId, CurrentGain);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Scale hit heat in conduction

With both 战斗升温 and 高速导热 selected, attack-hit heat still uses the unmodified AttackHeatGain in MachineCoreEffect.OnDamageDealt, because this tier only registers a modifier for movement heat. The resource text and the previous implementation both apply 高速导热 to all heat accumulation, so hit-based heat gain now stays at 3/4/5 instead of receiving the +75%/+100% gain.

Useful? React with 👍 / 👎.

{
if (_hasDamaged) return;
if (Damage <= 0 && KnockbackSpeed <= 0f && KnockbackDistance <= 0f) return;
if (_cachedPlayer == null) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve non-player targets for enemy beams

The updated lightning scene is configured as TargetableFactions = Enemy with Damage = 20, but both beam damage paths still only test _cachedPlayer. In ECoreAttackEffect's child beams this means the target checked is always the player, and DamageDispatcher rejects it for an enemy-only beam, so the configured lightning damage/knockback never applies to enemies. The beam target lookup needs to follow TargetableFactions like RotatingCube does, or this scene should be marked visual-only.

Useful? React with 👍 / 👎.

}
_wasMovingLastFrame = moving;

ApplyOverflowBuff();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Recompute overflow stats during release

When overclock heat is being drained by the core release buff, DisableHeatGainDuringBuff is true by default, so OnTick returns before this new overflow stat update runs. If heat falls back below MaxHeat while the release buff is still active, the previously boosted speed, attack speed, and incoming damage multiplier stay stuck until the buff fully ends instead of tracking the current overflow amount. Move the overflow recomputation before the heat-gain early return or avoid returning before stat cleanup.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/fx/RotatingCube.cs (1)

351-374: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

targetarea.Owner 的解析不一致,Owner 为 null 时击退会丢失喵。

第 353 行用 area.Owner ?? area 得到 target,第 358 行把 target 传给 DealDamage。但第 356 行的 alreadyInvincible 和第 373 行的 ApplyKnockback 都直接用 area.Owner as GameActor 喵。

如果 HitArea 所属节点是运行时 AddChild 添加的,Owner 会是 null 喵。这时 target 退化成 area 本身,DealDamage 可能仍然成功(内部会向上解析 GameActor),但第 373 行的 area.Owner as GameActor 为 null,击退直接被跳过喵。同一次命中里,伤害生效而击退不生效,行为不一致喵。

本 PR 的 scripts/effects/ECoreAttackEffect.cs 第 202-204 行对同样的场景做了多级回退解析。建议这里也统一解析成一个 GameActor 变量,全流程复用它喵~

🐛 建议的修复
             // 仅接受目标的 HitArea,避免敌人的攻击判定区等误触发
             if ((string)area.Name != "HitArea") return;
-            var target = area.Owner ?? area;
+            var hitActorResolved = area.Owner as GameActor
+                ?? area.GetParent() as GameActor
+                ?? area.GetParent()?.GetParent() as GameActor;
+            Node target = hitActorResolved ?? (Node)area;
             if (!AllowSelfDamage && DamageDispatcher.BelongsToActor(target, _attacker)) return;
 
-            bool alreadyInvincible = area.Owner is Actors.Heroes.MainCharacter mc && mc.IsHitInvincible;
+            bool alreadyInvincible = hitActorResolved is Actors.Heroes.MainCharacter mc && mc.IsHitInvincible;
 
             bool dealt = DamageDispatcher.DealDamage(target, Damage, GlobalPosition, _attacker,
                 DamageSource.DirectAttack, TargetableFactions, AllowSelfDamage, null);
@@
             if (!dealt) return;
 
-            if (!alreadyInvincible && area.Owner is GameActor hitActor)
-                ApplyKnockback(hitActor);
+            if (!alreadyInvincible && hitActorResolved != null)
+                ApplyKnockback(hitActorResolved);

对应地,第 360-366 行的日志判断也需要改用 hitActorResolved

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/fx/RotatingCube.cs` around lines 351 - 374, 统一命中目标解析逻辑:在当前
AreaEntered 处理流程中基于 area.Owner ?? area 解析并保存可用的 GameActor(参考 ECoreAttackEffect
的多级回退),然后让 alreadyInvincible、DealDamage 后的拒绝日志以及 ApplyKnockback 全部复用该变量,避免 Owner
为 null 时伤害成功但击退被跳过。
🧹 Nitpick comments (10)
scripts/ui/BuildSelectionWindow.cs (1)

175-193: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

建议加固数值解析与格式化喵。

这里有两个小隐患喵:

  1. Line 180 用 int.Parse。模板里写了超长数字(例如 {99999999999})时会抛 OverflowException,整个描述渲染都会炸掉喵。用 int.TryParse 失败就保留原文,和现有"无法解析保留原文"的策略一致喵~
  2. Line 189 的 ToString() 依赖当前区域性。区域性使用逗号小数分隔符时,12.5 会显示成 12,5,和卡面其他数字不一致喵。建议显式指定 CultureInfo.InvariantCulture
♻️ 建议改动
-                int index = int.Parse(match.Groups[2].Value);
+                if (!int.TryParse(match.Groups[2].Value, out int index))
+                    return match.Value; // 数字非法 → 保留原文
 
                 var values = effect.GetOverrideFloatArray(arrayName);
                 if (values == null || index < 0 || index >= values.Length)
                     return match.Value; // 无数据 → 保留原文
 
                 int tierIndex = Mathf.Clamp(stacks, 0, values.Length - 1);
 
                 // 修改器百分比为负(减容/缓速类)时,描述按数值大小显示(降低 10%,而非 -10%)
-                string valueText = Mathf.Abs(values[index]).ToString();
+                string valueText = Mathf.Abs(values[index])
+                    .ToString(System.Globalization.CultureInfo.InvariantCulture);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ui/BuildSelectionWindow.cs` around lines 175 - 193, Harden the
TierTokenRegex replacement by changing the index parsing in the template
substitution callback to use int.TryParse, returning match.Value when parsing
fails or overflows. Update the values[index] formatting to use
CultureInfo.InvariantCulture explicitly, preserving the existing absolute-value
and color-selection behavior.
scripts/builds/machine/MachineDeathEmberEffect.cs (1)

62-84: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

FreezeHeatGain 是共享布尔量,直接置 false 有风险喵。

ClearEmber 无条件把 _core.FreezeHeatGain 设为 false(Line 82)喵。MachineCoreEffect 的注释说这个标志"由外部效果设置",也就是设计上允许多个效果使用喵。以后再有第二个效果冻结热量获取时,余温结束就会顺手把别人的冻结也解掉喵。

现在只有这一个使用者,所以不阻塞合并喵。要更稳的话,可以在核心里改成计数式的 PushHeatFreeze() / PopHeatFreeze(),和 PauseManager 的做法一致喵~

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/builds/machine/MachineDeathEmberEffect.cs` around lines 62 - 84, 将
MachineCoreEffect 的共享 FreezeHeatGain 布尔状态改为类似 PauseManager 的计数式冻结接口,新增
PushHeatFreeze() 与 PopHeatFreeze() 并由计数决定实际状态;更新 MachineDeathEmberEffect 的
TriggerEmber 和 ClearEmber,分别调用对应接口,确保清理余温时只解除自身冻结而不影响其他效果。
构筑卡牌描述模板机制.md (1)

7-9: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

代码块补一个语言标识喵。

markdownlint 报了 MD040 喵。这两个围栏代码块没有语言标识,加上 text 就好了喵~

♻️ 建议改动
-```
+```text
 模板: {数组名:下标}    例: {GainValues:0}   简写: {0} ≡ {TierValues:0}
</details>


Also applies to: 13-21

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @构筑卡牌描述模板机制.md around lines 7 - 9, 为文档中的围栏代码块补充 text
语言标识,覆盖模板示例及同文档中另一个对应的代码块(当前标注范围 13-21)。保持代码块内容不变,仅将开围栏统一改为 ```text 以满足 MD040。


</details>

<!-- cr-comment:v1:8451862c02fa03da0b7def63 -->

_Source: Linters/SAST tools_

</blockquote></details>
<details>
<summary>scripts/effects/ECoreAttackEffect.cs (2)</summary><blockquote>

`141-171`: _🩺 Stability & Availability_ | _🔵 Trivial_ | _⚡ Quick win_

**遍历 `_actorTimers` 期间调用 `DealDamageToActor` 有枚举失效风险喵。**

第 158 行在 `foreach` 内部调用 `DealDamageToActor`,它会走到 `DamageDispatcher.DealDamage`。如果伤害结算同步触发了目标死亡、节点移除或碰撞状态变化,进而同步回调到 `AddActorRef`,就会向 `_actorTimers` **新增键**喵。

.NET 允许在枚举期间更新已有键的值和删除键,但**新增键**会让枚举器失效并抛 `InvalidOperationException` 喵。

建议先快照键列表再遍历,把这个风险彻底排除喵~



<details>
<summary>♻️ 建议的重构</summary>

```diff
         private void TickDamage(float dt)
         {
             if (_actorTimers.Count == 0) return;
 
             var dead = new List<GameActor>();
-            foreach (var (actor, timer) in _actorTimers)
+            var snapshot = new List<GameActor>(_actorTimers.Keys);
+            foreach (var actor in snapshot)
             {
+                if (!_actorTimers.TryGetValue(actor, out float timer)) continue;
+
                 if (!GodotObject.IsInstanceValid(actor) || actor.IsDead)
                 {
                     dead.Add(actor);
                     continue;
                 }
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/effects/ECoreAttackEffect.cs` around lines 141 - 171, Update
TickDamage to iterate over a snapshot of _actorTimers keys or entries instead of
enumerating the dictionary directly, while preserving the existing timer
updates, damage calls, and dead-actor cleanup. Ensure actors added to
_actorTimers during DealDamageToActor do not invalidate the active enumeration
and are handled on a subsequent tick.
```

</details>

<!-- cr-comment:v1:a5cbd151fe6ab20346578bcd -->

---

`302-332`: _🎯 Functional Correctness_ | _🔵 Trivial_ | _⚡ Quick win_

**`_lastHitNormal` 是残留状态,且从未被使用喵。**

第 302 行的 `_lastHitNormal` 是成员字段,每次调用都不重置。第 329-331 行的返回值依赖它:如果本次射线命中的结果里没有 `normal` 键,函数会拿**上一次**命中的法线来判定,返回一个陈旧的 `true` 喵。

而且 `BounceXAxisOnly` 只翻转 X 方向,根本不读法线喵。这个字段既是死状态又会污染判定结果喵。

建议直接返回命中结果,并删除该字段喵~



<details>
<summary>♻️ 建议的重构</summary>

```diff
-        private Vector2 _lastHitNormal = Vector2.Zero;
-
         /// <summary>
         /// 沿移动方向发射短射线检测前方非角色物理体(墙/障碍)。
-        /// 命中则记录法线并返回 true。
+        /// 命中非角色物理体则返回 true。
         /// </summary>
         private bool ProbeCollision(Vector2 from, float horizontalVelocity)
         {
@@
             var body = collider.As<GodotObject>();
             if (body is GameActor) return false;
-
-            if (result.TryGetValue("normal", out var normal))
-                _lastHitNormal = normal.AsVector2();
-            return _lastHitNormal != Vector2.Zero;
+            return true;
         }
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/effects/ECoreAttackEffect.cs` around lines 302 - 332, Remove the
unused _lastHitNormal field and update ProbeCollision to return true immediately
after confirming a non-GameActor collider was hit, without reading or storing
the ray result’s normal. Preserve the existing false returns for zero velocity,
no hit, and GameActor collisions.
```

</details>

<!-- cr-comment:v1:22bd14a9fafdba03dc80d3d0 -->

</blockquote></details>
<details>
<summary>scripts/effects/DotBurnEffect.cs (1)</summary><blockquote>

`97-105`: _🚀 Performance & Scalability_ | _🔵 Trivial_ | _⚡ Quick win_

**建议缓存 HitArea 查找结果喵~**

`GetHitCenterWorld` 在每次 `OnTick` 都会调用。当 `GetNodeOrNull<Area2D>("HitArea")` 失败时,会走 `FindChild(recursive: true)` 递归遍历目标的整个子树喵。灼烧默认持续 3 秒,每帧都做一次递归搜索,对多目标同时灼烧的场景会累积开销喵。

建议在 `OnApply` 时解析一次并缓存 `CollisionShape2D` 引用,`OnTick` 只读缓存喵。

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/effects/DotBurnEffect.cs` around lines 97 - 105, Update DotBurnEffect
so OnApply resolves and caches the target’s CollisionShape2D (including the
existing HitArea lookup fallback), then have GetHitCenterWorld or the OnTick
path use that cached reference instead of searching the target hierarchy each
tick; preserve the current fallback positions when the cached shape or HitArea
is unavailable.
```

</details>

<!-- cr-comment:v1:29e459159f082d148f3d33e2 -->

</blockquote></details>
<details>
<summary>scripts/effects/BriefcaseOpenEffect.cs (1)</summary><blockquote>

`110-113`: _📐 Maintainability & Code Quality_ | _🔵 Trivial_ | _💤 Low value_

**注释语义写反了喵。**

第 111 行注释写「不挂在本场景下,随本场景销毁而销毁」,但代码把节点加到 `world` 下,正是为了让它**不**随本场景销毁。类头文档也写的是「生成的特效独立存在(不随本场景销毁)」。两处矛盾会误导后续维护者喵。



<details>
<summary>📝 建议的注释修正</summary>

```diff
-                // 独立加入世界层:不挂在本场景下,随本场景销毁而销毁
+                // 独立加入世界层:不挂在本场景下,因此不随本场景销毁
                 world.AddChild(node2D);
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/effects/BriefcaseOpenEffect.cs` around lines 110 - 113, 修正 node2D 加入
world 的上一行注释语义,明确该特效独立挂载于世界层、不会随当前场景销毁,并与类头文档保持一致;仅更新注释,不改动 world.AddChild
或位置设置逻辑。
```

</details>

<!-- cr-comment:v1:6e7d30bb98c1c583496cc9cf -->

</blockquote></details>
<details>
<summary>scripts/fx/LightningBeam.cs (2)</summary><blockquote>

`196-207`: _📐 Maintainability & Code Quality_ | _🔵 Trivial_ | _⚡ Quick win_

**建议用 `RandomArcMode` 而不是 `_arcs.Count` 来选择分支喵。**

第 196 行用 `_arcs.Count > 0` 区分电弧模式与光束模式。如果随机电弧模式下某一帧 `_arcs` 恰好为空,代码会静默落到 `else` 分支,去调用 `UpdateBeam()` 和 `TryDamagePlayer()` 喵。

此时 `_ray` 为 null,`UpdateBeam` 在第 363 行直接 return,`_currentLength` 保持 0,`TryDamagePlayer` 的第 389 行判定必然失败喵。结果就是这一帧既没有视觉也没有伤害,而且不会有任何报错提示喵。

用模式标志判断可以让意图明确,也避免这种静默降级喵~



<details>
<summary>♻️ 建议的重构</summary>

```diff
-			if (_arcs.Count > 0)
+			if (RandomArcMode)
 			{
 				UpdateArcs();
 				if (!_hasDamaged && _pulseTotal - _timer >= GrowDuration)
 					TryDamageArcs();
 			}
```

```diff
 			_pulseTotal = GrowDuration + _pulseLifetime + FadeDuration;
-			if (_arcs.Count > 0)
+			if (RandomArcMode)
 			{
 				foreach (var arc in _arcs) arc.Sprite.QueueFree();
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/fx/LightningBeam.cs` around lines 196 - 207, Update the branch
selection in the beam update flow to use the RandomArcMode state instead of
_arcs.Count > 0. Keep UpdateArcs and TryDamageArcs in the arc-mode branch, and
UpdateBeam and TryDamagePlayer in the beam-mode branch, so an empty arc
collection cannot silently switch modes.
```

</details>

<!-- cr-comment:v1:f94b1e6df1a47e2bbf07f2f0 -->

---

`214-226`: _🚀 Performance & Scalability_ | _🔵 Trivial_ | _🏗️ Heavy lift_

**每个脉冲都重建全部 Sprite 与 ShaderMaterial,开销偏高喵。**

`StartPulse` 每次都把全部电弧 `QueueFree` 再重新 `SpawnRandomArcs`。`SpawnRandomArcs` 里每条电弧都会新建一个 `Sprite2D`、执行一次 `ShaderMaterial.Duplicate()`,还要发一条物理射线喵。

`ArcCount` 上限是 64,`MinLifetime` 下限是 0.05 秒。极端配置下每秒会产生数百次节点创建、材质复制和射线查询喵。`ECoreAttackEffect.tscn` 里同时挂了 10 个 `LightningBeam` 实例,开销会叠加喵。

建议复用已有的 `Sprite2D` 与材质,脉冲之间只更新 `Direction`、`TargetLength` 和 shader 的 `seed` 喵~

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/fx/LightningBeam.cs` around lines 214 - 226, 优化 StartPulse,避免每个脉冲通过
QueueFree 和 SpawnRandomArcs 重建全部电弧节点与材质;复用已有 Arc/Sprite2D 及其 ShaderMaterial。根据
ArcCount 增减或初始化可复用电弧,仅更新每条电弧的 Direction、TargetLength 和 shader
seed,并避免不必要的重复物理射线查询。
```

</details>

<!-- cr-comment:v1:5a92b82807daf6d205e42976 -->

</blockquote></details>
<details>
<summary>scripts/fx/RotatingCube.cs (1)</summary><blockquote>

`187-189`: _📐 Maintainability & Code Quality_ | _🔵 Trivial_ | _⚡ Quick win_

**建议移除或收敛 `[Cube Debug]` 调试日志喵。**

新增的三处 `GD.Print` 都带 `[Cube Debug]` 前缀,是调试残留喵。

第 322 行的问题最明显:它在**每一次** `BodyEntered` 都执行喵。弹幕在飞行途中会碰到地面、墙体、其他投掷物,触发频率很高喵。而且插值参数里还额外调用了一次 `DamageDispatcher.ResolveDamageReceiver`,这次调用**仅仅是为了打日志**喵。第 189 行也会为每个生成的 cube 打印一次喵。

建议用一个 `[Export] bool DebugLog` 开关包起来,或者直接删掉喵~





Also applies to: 322-323, 360-370

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/fx/RotatingCube.cs` around lines 187 - 189, 移除或收敛 RotatingCube 中所有带
“[Cube Debug]” 前缀的 GD.Print 调试日志,涵盖 ResolveAimTarget 附近的生成日志、BodyEntered
处理以及插值参数相关日志;不要为日志额外调用 DamageDispatcher.ResolveDamageReceiver。若保留日志,新增并使用一个
[Export] bool DebugLog 开关,仅在启用时输出。
```

</details>

<!-- cr-comment:v1:f1eb8ad63816ab7c6a78a199 -->

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @resources/builds/BuildMachine_A_010.tres:

  • Around line 12-15: Update the overclock description associated with
    AttackSpeedPercentPerHeat, DamageTakenPercentPerHeat, and SpeedPercentPerHeat so
    it accurately states the configured movement-speed, attack-speed, and
    damage-taken percentages; alternatively, set all three configuration values to
    the intended 2.0 value while preserving the existing overclock behavior.

In @resources/builds/BuildMachine_B_006.tres:

  • Around line 3-4: Configure EffectEntries for both BuildMachine_B_006.tres and
    BuildMachine_B_008.tres by adding AttackEffectEntry subresources referencing
    their intended effect scenes, then assign those subresources to each resource’s
    EffectEntries array so BuildSelectionManager.ApplyEffectBonuses can instantiate
    and apply the effects.

In @resources/items/Weapon_Throw_ECore.tres:

  • Around line 17-18: 将 Weapon_Throw_ECore.tres 中的 Notes
    字符串改为单行文本,或将其中的原始换行替换为转义序列 \n,确保 Notes 字符串正确闭合并可被 Godot 资源解析器加载。

In @scenes/builds/machine/MachineHeatFlowImpactEffect.tscn:

  • Line 10: 将 MachineHeatFlowImpactEffect 场景中的 ShowDebugRadius 设置为 false,确保
    MachineHeatFlowImpactEffect.CreateContactArea() 不创建
    ContactRadiusDrawer,也不会在运行时绘制调试圆。
  • Around line 8-9: 使 MachineHeatFlowImpactEffect 的 TargetCollisionMask 与
    TargetableFactions = 6 保持一致:若该效果应命中 WorldItem,将掩码扩展为包含 Godot layer 4,同时保留 Enemy
    所需的层;若设计上仅命中 Enemy,则将 TargetableFactions 调整为仅对应 Enemy。

In @scenes/managers/BuildSelectionManager.tscn:

  • Around line 43-47: Restore the RarityMultiplier values in the scene resource
    to the intended weights: keep Common at 3.0, set Rare to 1.0, and set Epic to
    0.3; do not add a Core entry, so its existing code default of 1.0 remains
    effective.

In @scripts/actors/heroes/attacks/PlayerAttackTemplate.cs:

  • Around line 276-285: 在初始化时序覆盖的代码中,先通过 GetPrimarySkillDefinition() 更新
    _activeWeaponSkill,再计算 _pendingSkipWarmupStart。确保跳过 Warmup 的偏移使用当前技能的
    WarmupDuration,并保留后续 _effectiveWarmup、_effectiveActive 和 _effectiveRecovery
    的新技能时序计算。

In @scripts/builds/buildcore/MachineCoreEffect.cs:

  • Around line 206-234: 修改 ApplyOverflowBuff 及其相关状态管理,仅在本效果实际处于超频并已接管属性时写入
    Speed、AttackSpeedMultiplier 和
    IncomingDamageMultiplier;用“上一帧是否应用超频”的状态记录进入与退出超频,仅在退出时还原一次,避免覆盖其他效果的修改。修正
    DisableHeatGainDuringBuff && _buffActive 的提前返回,使本帧仍能处理超频状态转移,并在 OnRemoved 中仅当
    _overflowApplied 为 true 时执行还原。

In @scripts/builds/machine/MachineBurstThrustEffect.cs:

  • Around line 26-27: Handle empty exported tier arrays across the machine
    effects: in scripts/builds/machine/MachineBurstThrustEffect.cs lines 26-27,
    update CurrentKnockback and CurrentDamageBonus; in
    scripts/builds/machine/MachineDeathEmberEffect.cs line 24, update
    CurrentHoldDuration; in scripts/builds/machine/MachineDecayDelayEffect.cs line
    20, update CurrentPercent; and in
    scripts/builds/machine/MachineHeatFlowImpactEffect.cs line 39, update
    CurrentRadius. Return a safe zero fallback when each array is empty, otherwise
    clamp _tier to a valid array index; ensure the heat-flow effect skips area
    creation when its radius fallback is zero, and prevent OnStackRefreshed from
    producing a negative _tier.
  • Around line 66-85: Update OnDamageResolved to return immediately when target
    is null before setting _armed or accessing target.TakeDamage,
    target.GlobalPosition, or target.ActiveImmunities. Preserve the
    one-trigger-per-buff behavior for valid GameActor targets while allowing later
    attacks after non-GameActor hits.

In @scripts/builds/machine/MachineHeatFlowImpactEffect.cs:

  • Around line 132-162: Update TickDamage to avoid mutating _actorTimers while
    enumerating it: first snapshot or otherwise iterate the existing keys, use
    TryGetValue before processing each actor, and defer removals through the
    existing dead list. Ensure DealDamageToActor can trigger OnBodyExited,
    OnAreaExited, or AddActorRef without modifying the collection being traversed.

In @scripts/effects/DotBurnEffect.cs:

  • Around line 73-76: 在 DotBurnEffect 的 tick 伤害逻辑中,调用 Actor.TakeDamage 前统一验证
    Actor 不为 null 且 IsInstanceValid(Actor) 为 true;目标已移除或失效时直接跳过该次伤害,避免 _Process
    抛出异常。

In @scripts/effects/ECoreAttackEffect.cs:

  • Around line 247-259: 为 ECoreAttackEffect 增加公开的 Attacker 属性,并在 ResolveAttacker
    中优先保留已传入的攻击者,只有未设置时才执行父节点兄弟节点扫描;同时在 BriefcaseOpenEffect.SpawnEffect 创建
    ECoreAttackEffect 时赋值 Attacker,确保投掷生成效果能正确排除投掷者并传递伤害来源。

In @scripts/fx/LightningBeam.cs:

  • Around line 74-120: 延迟首次随机电弧生成,避免在 LightningBeam._Ready 中直接调用 SpawnRandomArcs
    时读取尚未完成的 GlobalPosition 和 Rotation。参考 ECoreAttackEffect 的首帧初始化方式,在 _Ready
    中仅完成节点与参数准备,并通过首个 _Process 帧触发 SpawnRandomArcs;确保 RandomArcMode=false
    的现有初始化流程不受影响,并移除或保护重复生成。
  • Around line 240-264: 将 LightningBeam 的墙体探测碰撞掩码改为显式导出的配置属性,供 ProbeWallDistance
    直接使用,移除对随机电弧模式下始终为空的 _ray.CollisionMask 及硬编码 4 的依赖;同时保留普通模式下与 RayCast2D
    配置一致的现有行为,必要时在初始化阶段复用该节点的掩码作为默认值。

In @scripts/fx/RotatingCube.cs:

  • Around line 326-333: 将 scripts/fx/RotatingCube.cs#L326-L333 中的 AirWall 名称比较改为对
    air_wall 节点组调用 IsInGroup("air_wall"),并移除冗余的 body is Node node 检查;同时将
    scripts/items/world/RigidBodyWorldItemEntity.cs#L1259-L1263
    的相同名称判断改为同一组判定,并更新对应关卡场景将空气墙节点加入 air_wall 组。

In @scripts/items/world/RigidBodyWorldItemEntity.cs:

  • Around line 718-736: Update the wall-hit branch around CheckWallHit to reset
    _isDropping and call SetShadowVisible(true), matching the normal landing branch
    before starting the hide timer. Also revise the nearby comment to describe the
    actual AirWall-only detection and stop-then-hide behavior rather than claiming
    all non-GameActor bodies are immediately destroyed.

In @scripts/ui/BuildCard.cs:

  • Line 18: Update the theme font-size override for DescLabel to use the
    RichTextLabel-specific theme key instead of Label’s “font_size” key, while
    preserving the existing size value and override flow.

In @scripts/ui/CoreHUD.cs:

  • Around line 59-65: 在 CoreHUD 中更新 factor 的计算,使 HeatFillBar 的最终缩放不超过已声明的 1.5
    倍上限;对溢出比例或计算结果应用上限限制,并保留 MaxHeat 为零时的现有安全行为。

Outside diff comments:
In @scripts/fx/RotatingCube.cs:

  • Around line 351-374: 统一命中目标解析逻辑:在当前 AreaEntered 处理流程中基于 area.Owner ?? area
    解析并保存可用的 GameActor(参考 ECoreAttackEffect 的多级回退),然后让 alreadyInvincible、DealDamage
    后的拒绝日志以及 ApplyKnockback 全部复用该变量,避免 Owner 为 null 时伤害成功但击退被跳过。

Nitpick comments:
In @scripts/builds/machine/MachineDeathEmberEffect.cs:

  • Around line 62-84: 将 MachineCoreEffect 的共享 FreezeHeatGain 布尔状态改为类似
    PauseManager 的计数式冻结接口,新增 PushHeatFreeze() 与 PopHeatFreeze() 并由计数决定实际状态;更新
    MachineDeathEmberEffect 的 TriggerEmber 和
    ClearEmber,分别调用对应接口,确保清理余温时只解除自身冻结而不影响其他效果。

In @scripts/effects/BriefcaseOpenEffect.cs:

  • Around line 110-113: 修正 node2D 加入 world
    的上一行注释语义,明确该特效独立挂载于世界层、不会随当前场景销毁,并与类头文档保持一致;仅更新注释,不改动 world.AddChild 或位置设置逻辑。

In @scripts/effects/DotBurnEffect.cs:

  • Around line 97-105: Update DotBurnEffect so OnApply resolves and caches the
    target’s CollisionShape2D (including the existing HitArea lookup fallback), then
    have GetHitCenterWorld or the OnTick path use that cached reference instead of
    searching the target hierarchy each tick; preserve the current fallback
    positions when the cached shape or HitArea is unavailable.

In @scripts/effects/ECoreAttackEffect.cs:

  • Around line 141-171: Update TickDamage to iterate over a snapshot of
    _actorTimers keys or entries instead of enumerating the dictionary directly,
    while preserving the existing timer updates, damage calls, and dead-actor
    cleanup. Ensure actors added to _actorTimers during DealDamageToActor do not
    invalidate the active enumeration and are handled on a subsequent tick.
  • Around line 302-332: Remove the unused _lastHitNormal field and update
    ProbeCollision to return true immediately after confirming a non-GameActor
    collider was hit, without reading or storing the ray result’s normal. Preserve
    the existing false returns for zero velocity, no hit, and GameActor collisions.

In @scripts/fx/LightningBeam.cs:

  • Around line 196-207: Update the branch selection in the beam update flow to
    use the RandomArcMode state instead of _arcs.Count > 0. Keep UpdateArcs and
    TryDamageArcs in the arc-mode branch, and UpdateBeam and TryDamagePlayer in the
    beam-mode branch, so an empty arc collection cannot silently switch modes.
  • Around line 214-226: 优化 StartPulse,避免每个脉冲通过 QueueFree 和 SpawnRandomArcs
    重建全部电弧节点与材质;复用已有 Arc/Sprite2D 及其 ShaderMaterial。根据 ArcCount 增减或初始化可复用电弧,仅更新每条电弧的
    Direction、TargetLength 和 shader seed,并避免不必要的重复物理射线查询。

In @scripts/fx/RotatingCube.cs:

  • Around line 187-189: 移除或收敛 RotatingCube 中所有带 “[Cube Debug]” 前缀的 GD.Print
    调试日志,涵盖 ResolveAimTarget 附近的生成日志、BodyEntered 处理以及插值参数相关日志;不要为日志额外调用
    DamageDispatcher.ResolveDamageReceiver。若保留日志,新增并使用一个 [Export] bool DebugLog
    开关,仅在启用时输出。

In @scripts/ui/BuildSelectionWindow.cs:

  • Around line 175-193: Harden the TierTokenRegex replacement by changing the
    index parsing in the template substitution callback to use int.TryParse,
    returning match.Value when parsing fails or overflows. Update the values[index]
    formatting to use CultureInfo.InvariantCulture explicitly, preserving the
    existing absolute-value and color-selection behavior.

In @构筑卡牌描述模板机制.md:

  • Around line 7-9: 为文档中的围栏代码块补充 text 语言标识,覆盖模板示例及同文档中另一个对应的代码块(当前标注范围
    13-21)。保持代码块内容不变,仅将开围栏统一改为 ```text 以满足 MD040。

</details>

<details>
<summary>🪄 Autofix</summary>

Fix all unresolved CodeRabbit comments on this PR:

- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: Organization UI

**Review profile**: CHILL

**Plan**: Pro Plus

**Run ID**: `9779e4e1-e6df-406b-8983-ac57e7d52311`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between b45bb0638cd39fb73de64ced7e03def867e85cef and 4dfca9137a0cbce06eb9f9c8690c21388b3894dc.

</details>

<details>
<summary>⛔ Files ignored due to path filters (86)</summary>

* `assets/BuildIcon/Machine_B_001_快速放热.png` is excluded by `!**/*.png`
* `assets/BuildIcon/Machine_B_002_缓速放热.png` is excluded by `!**/*.png`
* `assets/BuildIcon/Machine_B_003_死亡余温.png` is excluded by `!**/*.png`
* `assets/BuildIcon/Machine_B_004_热流冲击.png` is excluded by `!**/*.png`
* `assets/BuildIcon/Machine_B_005_爆发推力.png` is excluded by `!**/*.png`
* `assets/BuildIcon/Machine_B_006_热能抽离.png` is excluded by `!**/*.png`
* `assets/BuildIcon/Machine_B_007_燃烧效率.png` is excluded by `!**/*.png`
* `assets/BuildIcon/Machine_B_008_热能闪避.png` is excluded by `!**/*.png`
* `assets/BuildIcon/Machine_B_009_齿轮关节.png` is excluded by `!**/*.png`
* `assets/BuildIcon/Machine_B_010_延迟损伤.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_01.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_02.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_03.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_04.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_05.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_06.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_07.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_08.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_09.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_10.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_11.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_12.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_13.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_14.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_15.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_16.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_17.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_18.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_19.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_20.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_21.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_22.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_23.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_24.png` is excluded by `!**/*.png`
* `assets/effect/AttackEffect/burn_b/BurnB_25.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0000.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0001.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0002.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0003.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0004.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0005.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0006.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0007.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0008.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0009.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0010.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0011.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0012.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0013.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0014.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0015.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0016.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0017.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0018.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0019.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0020.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0021.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0022.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0023.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0024.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0025.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/choose/时间轴 1_0026.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0000.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0001.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0002.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0003.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0004.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0005.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0006.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0007.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0008.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0009.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0010.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0011.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0012.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0013.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0014.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0015.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0016.png` is excluded by `!**/*.png`
* `assets/objects/briefcase/open/时间轴 1_0017.png` is excluded by `!**/*.png`
* `assets/weapons/回旋镖.png` is excluded by `!**/*.png`
* `assets/weapons/滚雷.png` is excluded by `!**/*.png`
* `data/characters.csv` is excluded by `!**/*.csv`
* `data/items.csv` is excluded by `!**/*.csv`
* `data/skills.csv` is excluded by `!**/*.csv`
* `新构筑machine卡牌效果.csv` is excluded by `!**/*.csv`

</details>

<details>
<summary>📒 Files selected for processing (99)</summary>

* `project.godot`
* `resources/builds/BuildMachine_A_001.tres`
* `resources/builds/BuildMachine_A_002.tres`
* `resources/builds/BuildMachine_A_003.tres`
* `resources/builds/BuildMachine_A_004.tres`
* `resources/builds/BuildMachine_A_005.tres`
* `resources/builds/BuildMachine_A_006.tres`
* `resources/builds/BuildMachine_A_007.tres`
* `resources/builds/BuildMachine_A_008.tres`
* `resources/builds/BuildMachine_A_009.tres`
* `resources/builds/BuildMachine_A_010.tres`
* `resources/builds/BuildMachine_B_001.tres`
* `resources/builds/BuildMachine_B_002.tres`
* `resources/builds/BuildMachine_B_003.tres`
* `resources/builds/BuildMachine_B_004.tres`
* `resources/builds/BuildMachine_B_005.tres`
* `resources/builds/BuildMachine_B_006.tres`
* `resources/builds/BuildMachine_B_008.tres`
* `resources/effects/BoomerangAttackEffect.tscn`
* `resources/effects/BriefcaseOpenEffect.tscn`
* `resources/effects/CubeDataBoom.tscn`
* `resources/effects/DotBurnEffect.tscn`
* `resources/effects/ECoreAttackEffect.tscn`
* `resources/effects/FireWall.tscn`
* `resources/items/Weapon_Stab_drill.tres`
* `resources/items/Weapon_Throw_Briefcase.tres`
* `resources/items/Weapon_Throw_ECore.tres`
* `resources/items/Weapon_Throw_EmojiBomb.tres`
* `resources/items/skills/WeaponSkill_Stab_Drill.tres`
* `scenes/Stage_test.tscn`
* `scenes/actors/characters/Enemy_B1_fat.tscn`
* `scenes/actors/characters/Enemy_B2_fat02.tscn`
* `scenes/actors/characters/Enemy_D1_corpDoneB.tscn`
* `scenes/actors/characters/Enemy_D1_drone.tscn`
* `scenes/actors/characters/Enemy_D1_netAdmin.tscn`
* `scenes/actors/characters/Enemy_Normal_guard3.tscn`
* `scenes/actors/characters/main_character.tscn`
* `scenes/actors/etc/BriefcaseHoldingAnimation.tscn`
* `scenes/actors/etc/Briefcase_attack.tscn`
* `scenes/actors/etc/Briefcase_defense.tscn`
* `scenes/actors/etc/EmojiBoomAnimation.tscn`
* `scenes/builds/MachineCore.tscn`
* `scenes/builds/machine/MachineBurstThrustEffect.tscn`
* `scenes/builds/machine/MachineDeathEmberEffect.tscn`
* `scenes/builds/machine/MachineHeatFlowCycleEffect.tscn`
* `scenes/builds/machine/MachineHeatFlowImpactEffect.tscn`
* `scenes/builds/machine/MachineHighSpeedConductionEffect.tscn`
* `scenes/builds/machine/MachineModifyHeatDrainEffect.tscn`
* `scenes/builds/machine/MachineOverclockEffect.tscn`
* `scenes/builds/machine/MachineScorchingFeedbackEffect.tscn`
* `scenes/managers/BuildSelectionManager.tscn`
* `scenes/objects/Animation_drone_ultimate.tscn`
* `scenes/ui/components/BuildCard.tscn`
* `scenes/ui/hud/BuildCoreHUD.tscn`
* `scenes/weapons/Weapon_Throw_boomerang.tscn`
* `scenes/weapons/Weapon_Throw_briefcase.tscn`
* `scenes/weapons/Weapon_Throw_eCore.tscn`
* `scenes/weapons/Weapon_Throw_metalSpike.tscn`
* `scenes/weapons/Weapon_Throw_smokeGrenade.tscn`
* `scripts/actors/enemies/EnemyD1NetAdmin.cs`
* `scripts/actors/heroes/MainCharacter.cs`
* `scripts/actors/heroes/PlayerItemAttachment.cs`
* `scripts/actors/heroes/SamplePlayer.cs`
* `scripts/actors/heroes/attacks/PlayerAttackTemplate.cs`
* `scripts/actors/heroes/attacks/PlayerComboSkipWarmupAttack.cs`
* `scripts/actors/heroes/states/PlayerIdleHoldingState.cs`
* `scripts/actors/heroes/states/PlayerRunHoldingState.cs`
* `scripts/builds/buildcore/MachineCoreEffect.cs`
* `scripts/builds/machine/MachineBurstThrustEffect.cs`
* `scripts/builds/machine/MachineDeathEmberEffect.cs`
* `scripts/builds/machine/MachineDecayDelayEffect.cs`
* `scripts/builds/machine/MachineHeatFlowCycleEffect.cs`
* `scripts/builds/machine/MachineHeatFlowImpactEffect.cs`
* `scripts/builds/machine/MachineHeatRecoveryEffect.cs`
* `scripts/builds/machine/MachineHighSpeedConductionEffect.cs`
* `scripts/builds/machine/MachineInertiaDriveEffect.cs`
* `scripts/builds/machine/MachineModifyHeatCapEffect.cs`
* `scripts/builds/machine/MachineModifyHeatDrainEffect.cs`
* `scripts/builds/machine/MachineOverclockEffect.cs`
* `scripts/builds/machine/MachineScorchingFeedbackEffect.cs`
* `scripts/controllers/SpineController.gd`
* `scripts/core/GameActor.cs`
* `scripts/core/effects/AfterimageController.gd`
* `scripts/effects/BriefcaseOpenEffect.cs`
* `scripts/effects/DotBurnEffect.cs`
* `scripts/effects/ECoreAttackEffect.cs`
* `scripts/effects/MechGloveEffect.cs`
* `scripts/fx/LightningBeam.cs`
* `scripts/fx/RotatingCube.cs`
* `scripts/items/world/RigidBodyWorldItemEntity.cs`
* `scripts/managers/BuildSelectionManager.cs`
* `scripts/systems/BuildEffectDefinition.cs`
* `scripts/ui/BuildCard.cs`
* `scripts/ui/BuildSelectionWindow.cs`
* `scripts/ui/CoreHUD.cs`
* `scripts/ui/FloatingDamageText.cs`
* `shaders/lightning_beam.tscn`
* `shaders/materials/lightning_beam.gdshader`
* `构筑卡牌描述模板机制.md`

</details>

<details>
<summary>💤 Files with no reviewable changes (1)</summary>

* resources/items/Weapon_Stab_drill.tres

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread resources/builds/BuildMachine_A_010.tres
Comment on lines +3 to +4
[ext_resource type="Script" uid="uid://3bb6nng4vb53" path="res://scripts/systems/BuildEffectDefinition.cs" id="1_script"]
[ext_resource type="Script" uid="uid://fd5076f50ca0" path="res://scripts/actors/enemies/attacks/AttackEffectEntry.cs" id="1_uef0n"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

为 B006 和 B008 配置 EffectEntries 喵。

当前两个资源都没有 EffectEntries 喵。BuildSelectionManager.ApplyEffectBonuses 只会在该数组非空时实例化并应用 ActorEffect 喵。选择这两张卡只会增加 _pickedEffectIds,不会应用卡牌效果,恢复构筑状态时也不会应用喵。

  • resources/builds/BuildMachine_B_006.tres#L3-L4: 添加引用目标效果场景的 AttackEffectEntry 子资源,并设置 EffectEntries 喵。
  • resources/builds/BuildMachine_B_008.tres#L3-L4: 添加引用目标效果场景的 AttackEffectEntry 子资源,并设置 EffectEntries 喵。
📍 Affects 2 files
  • resources/builds/BuildMachine_B_006.tres#L3-L4 (this comment)
  • resources/builds/BuildMachine_B_008.tres#L3-L4
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@resources/builds/BuildMachine_B_006.tres` around lines 3 - 4, Configure
EffectEntries for both BuildMachine_B_006.tres and BuildMachine_B_008.tres by
adding AttackEffectEntry subresources referencing their intended effect scenes,
then assign those subresources to each resource’s EffectEntries array so
BuildSelectionManager.ApplyEffectBonuses can instantiate and apply the effects.

Comment on lines +17 to +18
Notes = "投掷的瞬间破坏并生成点击核心
"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

path = Path("resources/items/Weapon_Throw_ECore.tres")
text = path.read_text(encoding="utf-8")
raw_multiline = 'Notes = "投掷的瞬间破坏并生成点击核心\n"'
print(f"raw multiline Notes present: {raw_multiline in text}")
PY

Repository: Project-N-E-K-O/K.U.R.O

Length of output: 195


🌐 Web query:

Godot Resource .tres parser double quote string raw newline variant

💡 Result:

In Godot.tres (and.tscn) files, string values are defined within double quotes (e.g., key = "value") [1][2][3]. The parser handles these strings by supporting standard escape sequences, such as \n for a newline character [4][5]. Key points regarding the.tres string format and parser behavior include: 1. Escape Sequences: Within a quoted string in a.tres file, the backslash () acts as an escape character [4]. Common sequences like \n (newline), \t (tab), and \ (escaped backslash) are interpreted by the resource loader [4]. 2. Raw Newlines:.tres files generally do not support "raw" (literal) newlines inside a quoted string unless they are escaped [1][2]. If a newline character appears literally within a set of double quotes without escaping, the parser will likely encounter a syntax error, as Godot's text resource parser expects string values to be defined on a single logical line or properly escaped [1][2]. 3. Parsing Mechanism: The text resource parsing is handled primarily by the ResourceFormatLoaderText class (in resource_format_text.cpp) [1][3]. Unlike GDScript, which allows for multiline strings using triple-double quotes (""") [5], the.tres file format structure is stricter and primarily relies on standard double-quoted strings where literal control characters are represented via escape sequences [1][2]. If you are manually editing.tres files, you should use the \n escape sequence to represent a newline within a string value to ensure the parser correctly interprets it [4][5]. If you are generating these files programmatically, ensure that your serialization logic escapes newline characters before writing the string to the file [1].

Citations:


🌐 Web query:

Godot ResourceFormatLoaderText string parsing raw newline variant variant_parser error

💡 Result:

In Godot, parsing errors involving ResourceFormatLoaderText and the VariantParser are commonly triggered by syntax mismatches in text-based resource files (.tres,.tscn), such as unescaped characters, incorrect formatting of sub-resources, or unexpected newlines in contexts where the parser expects a specific token [1][2][3]. The VariantParser is the core utility used by ResourceFormatLoaderText to interpret the text-based structures of these files [1][4]. When it encounters a "raw newline" or a token it does not expect (such as a missing bracket or an incorrectly formatted tag), it throws a parse error [1][2][3]. Key insights into these errors: 1. Syntax Expectations: The parser is strict regarding the structure of text resources, which must start with specific headers like [gd_resource ...] or [gd_scene ...]. If a file is edited manually or saved with invalid characters, missing closing brackets, or improper indentation, the parser will fail [2][3]. 2. Context-Specific Parser Behavior: Issues have historically arisen where certain functions, like preload() in GDScript, used a more restrictive parsing ruleset than standard load() calls, leading to errors when newlines were introduced in certain formatting styles [5]. This was notably resolved in later versions of Godot [5]. 3. The "TextFile" Resource Hack: In Godot 3.x, the "TextFile" resource type was an internal editor utility rather than a robust public API. Attempting to use it as a general-purpose text handler often caused instability, cache conflicts, and parse errors because it was not designed for standard runtime resource management [2][6][7]. This type was subsequently removed from the public API in Godot 4.0 [2]. If you are encountering this error: - Verify file formatting: Ensure your.tres or.tscn file begins with the correct header and that all brackets are closed [2][3]. - Escape characters: Ensure that special characters within strings are correctly escaped if the parser is failing on unexpected characters [3]. - Avoid "TextFile": If you are on Godot 3.x, do not rely on "TextFile" resources. Use standard FileAccess to read and write text data, which is the supported method for handling arbitrary text files [7]. - Update/Consistency: Ensure that the file was not created on a platform with different line-ending conventions (CRLF vs. LF) that might conflict with the parser, though Godot is generally resilient to these [6].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

git ls-files resources/items/Weapon_Throw_ECore.tres
# Inspect surrounding .tres format metadata and the exact Notes line without executing repo code.
if command -v od >/dev/null 2>&1; then
  od -c resources/items/Weapon_Throw_ECore.tres | sed -n '1,80p'
else
  cat -A resources/items/Weapon_Throw_ECore.tres | sed -n '1,40p'
fi

Repository: Project-N-E-K-O/K.U.R.O

Length of output: 2209


Notes 改为单行文本或 \n

Notes = "..." 里直接包含了原始换行喵。这样会让 Godot 的资源解析器认为字符串未终结而报错喵。改成单行或把换行写成 \n,避免 Weapon_Throw_ECore.tres 无法加载喵。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@resources/items/Weapon_Throw_ECore.tres` around lines 17 - 18, 将
Weapon_Throw_ECore.tres 中的 Notes 字符串改为单行文本,或将其中的原始换行替换为转义序列 \n,确保 Notes
字符串正确闭合并可被 Godot 资源解析器加载。

Comment thread scenes/builds/machine/MachineHeatFlowImpactEffect.tscn Outdated
Comment thread scenes/builds/machine/MachineHeatFlowImpactEffect.tscn Outdated
Comment on lines +240 to +264
/// <summary>
/// 沿 dir 方向发射射线探测墙壁(避开角色),返回可延伸的最大长度。
/// 碰撞层复用场景中 RayCast2D 的配置。
/// </summary>
private float ProbeWallDistance(float dir, float maxLen)
{
var space = GetWorld2D().DirectSpaceState;
float worldAngle = Rotation + dir;
var query = new PhysicsRayQueryParameters2D
{
From = GlobalPosition,
To = GlobalPosition + new Vector2(Mathf.Cos(worldAngle), Mathf.Sin(worldAngle)) * maxLen,
CollideWithBodies = true,
CollideWithAreas = false,
CollisionMask = _ray?.CollisionMask ?? 4,
};
var result = space.IntersectRay(query);
if (result.Count == 0 || !result.TryGetValue("collider", out var collider))
return maxLen;
if (collider.As<GodotObject>() is GameActor)
return maxLen;
return result.TryGetValue("position", out var pos)
? GlobalPosition.DistanceTo(pos.AsVector2())
: maxLen;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

随机电弧模式下 _ray 恒为 null,碰撞掩码被硬编码成 4 喵。

第 242 行注释说「碰撞层复用场景中 RayCast2D 的配置」,但这句话在随机电弧模式下永远不成立喵。

SpawnRandomArcs 只在 RandomArcMode == true 时被调用(第 89 行和第 224 行)。而 _ray = GetNodeOrNull<RayCast2D>("RayCast2D") 只出现在第 93 行的 else 分支里喵。所以在随机电弧模式下 _ray 永远是 null,第 254 行的 _ray?.CollisionMask ?? 4 恒等于 4 喵。

后果是墙体探测固定只检测第 3 个碰撞层。若项目的墙体不在该层,电弧就会穿墙;若该层上有非墙体的物理体,电弧会被错误截断喵。

建议把碰撞掩码提升为显式导出属性,不要依赖一个在该模式下不存在的节点喵~

🐛 建议的修复
 		[ExportCategory("Plasma")]
 		/// <summary>随机电弧模式:以节点为中心向 360° 随机角度生成 ArcCount 条闪电。</summary>
 		[Export] public bool RandomArcMode = false;
 		[Export(PropertyHint.Range, "1,64,1")] public int ArcCount = 1;
+		/// <summary>随机电弧模式下墙体探测使用的碰撞掩码(该模式无 RayCast2D 子节点可复用)。</summary>
+		[Export(PropertyHint.Layers2DPhysics)] public uint WallProbeMask = 4;
 		/// <summary>
 		/// 沿 dir 方向发射射线探测墙壁(避开角色),返回可延伸的最大长度。
-		/// 碰撞层复用场景中 RayCast2D 的配置。
+		/// 碰撞层优先复用场景中 RayCast2D 的配置,随机电弧模式下使用 WallProbeMask。
 		/// </summary>
@@
-				CollisionMask = _ray?.CollisionMask ?? 4,
+				CollisionMask = _ray?.CollisionMask ?? WallProbeMask,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/fx/LightningBeam.cs` around lines 240 - 264, 将 LightningBeam
的墙体探测碰撞掩码改为显式导出的配置属性,供 ProbeWallDistance 直接使用,移除对随机电弧模式下始终为空的 _ray.CollisionMask
及硬编码 4 的依赖;同时保留普通模式下与 RayCast2D 配置一致的现有行为,必要时在初始化阶段复用该节点的掩码作为默认值。

Comment on lines +326 to +333
// 仅 AirWall(空气墙)拦截销毁,其他物理体(地面/障碍/投掷物)不拦截
if (body is not GameActor
&& body is Node node
&& string.Equals((string)node.Name, "AirWall", System.StringComparison.OrdinalIgnoreCase))
{
SpawnDestroyEffect();
QueueFree();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 统计仓库中 AirWall 相关的节点定义与名称判定,评估改造范围
echo "=== 场景中的 AirWall 节点 ==="
rg -n --glob '*.tscn' 'name="AirWall'

echo "=== 代码中按名称判定 AirWall 的位置 ==="
rg -n --glob '*.cs' --glob '*.gd' 'AirWall'

echo "=== 现有 air_wall 组的使用情况 ==="
rg -n 'air_wall'

Repository: Project-N-E-K-O/K.U.R.O

Length of output: 185


🏁 Script executed:

#!/bin/bash
set +e

echo "=== repository files containing AirWall ==="
rg -n 'AirWall|"AirWall|AirWall' . || true

echo "=== repository files containing air_wall ==="
rg -n 'air_wall|Air_Wall' . || true

echo "=== candidate C# files ==="
git ls-files '*.cs' | sed -n '1,120p'

echo "=== relevant file excerpts if present ==="
for f in scripts/fx/RotatingCube.cs scripts/items/world/RigidBodyWorldItemEntity.cs; do
  if [ -f "$f" ]; then
    echo "--- $f exists, line count ---"
    wc -l "$f"
    echo "--- $f relevant lines ---"
    nl -ba "$f" | sed -n '300,345p'
    echo "--- $f relevant lines second file ---"
    nl -ba "$f" | sed -n '1245,1272p'
  else
    echo "--- $f missing ---"
  fi
done

Repository: Project-N-E-K-O/K.U.R.O

Length of output: 18081


🌐 Web query:

Godot add_child duplicate names add suffix @ suffix documentation

💡 Result:

In Godot, sibling nodes are required to have unique names [1][2]. When you call add_child(node) and the name of the new child conflicts with an existing sibling, the engine automatically renames the new node to maintain uniqueness [3][4][5]. The specific naming behavior is controlled by the force_readable_name argument (formerly legible_unique_name in older versions) [6][2][7]: - By default (force_readable_name = false): Godot assigns a dummy, machine-generated name, typically featuring the @ character (e.g., @Node@123) [1][8][2]. This approach is used because it is computationally efficient and avoids complex checks against existing sibling names [9][2]. - When force_readable_name = true: Godot attempts to preserve the original name of the node but appends a numerical suffix if a collision occurs (e.g., Node2). This operation is more performance-intensive, which is why it is not the default for runtime additions [9][2]. Important notes regarding this behavior: - Character Restrictions: The @ character is reserved by the engine for these auto-generated unique names [10][3]. If you manually attempt to set a node's name to a string containing @, the engine will strip or reject it during validation [10][3]. - Performance: Using force_readable_name = true is generally recommended only when human-readable debugging is required, as the necessary name-collision checks can impact performance when adding many nodes at once [8][9][2]. - NodePath Stability: Because node names are used in NodePath strings, reliance on auto-generated @ names can be fragile if the order or timing of node creation changes [4][5]. It is often better to rely on node types, groups, or direct references rather than specific node names [4][5][11].

Citations:


🏁 Script executed:

#!/bin/bash
set +e

awk '112,148 { printf "%d\t%s\n", NR, $0 }' scenes/levels/A1.tscn
awk '202,210 { printf "%d\t%s\n", NR, $0 }' scenes/levels/C2.tscn
awk '168,180 { printf "%d\t%s\n", NR, $0 }' scripts/fx/RotatingCube.cs
awk '1255,1264 { printf "%d\t%s\n", NR, $0 }' scripts/items/world/RigidBodyWorldItemEntity.cs

echo "=== Godot project hints ==="
for f in project.godot .godot/global_script_class_cache.cfg; do
  [ -f "$f" ] && { echo "--- $f ---"; sed -n '1,180p' "$f"; }
done

echo "=== GlobalClass / air_wall group occurrences ==="
rg -n 'GlobalClass|group|Groups|air_wall|AirWall' --glob '*.cs' scripts scripts/*.cs 2>/dev/null || true

Repository: Project-N-E-K-O/K.U.R.O

Length of output: 50380


🏁 Script executed:

#!/bin/bash

echo "=== RotatingCube relevant lines ==="
awk '306,333 { printf "%d\t%s\n", NR, $0 }' scripts/fx/RotatingCube.cs

echo "=== RigidBodyWorldItemEntity AirWall relevant lines ==="
awk '1237,1265 { printf "%d\t%s\n", NR, $0 }' scripts/items/world/RigidBodyWorldItemEntity.cs

echo "=== current global group declarations in C# classes ==="
rg -n 'GlobalClass|Godot.Register|RegisterClass|AddToGroup|\["groups"|groups\s*=' --glob '*.cs' scripts || true

echo "=== Godot project/global data around GlobalClass/cache if present ==="
mkdir -p /tmp/kuroc_check
for f in project.godot .godot/global_script_class_cache.cfg .godot/editor/global_script_class_cache.cfg; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    rg -n 'GlobalClass|RegisterClass|AddToGroup|groups|AirWall|air_wall' "$f" || true
  fi
done

Repository: Project-N-E-K-O/K.U.R.O

Length of output: 50379


用节点组代替 "AirWall" 名称判断喵。 当前判定绑定到了场景节点名,名称修改或节点重名时都会让空气墙拦截漏判或只命中第一面喵。

两处共同改为把空气墙节点加入 air_wall 组,并用 IsInGroup("air_wall") 判断喵。需要同时更新对应的关卡场景。

  • scripts/fx/RotatingCube.cs#L326-L333:把名称比较换成组判定,并删除冗余的 body is Node node 检查喵。
  • scripts/items/world/RigidBodyWorldItemEntity.cs#L1261:把名称比较换成同一组判定喵。
📍 Affects 2 files
  • scripts/fx/RotatingCube.cs#L326-L333 (this comment)
  • scripts/items/world/RigidBodyWorldItemEntity.cs#L1259-L1263
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/fx/RotatingCube.cs` around lines 326 - 333, 将
scripts/fx/RotatingCube.cs#L326-L333 中的 AirWall 名称比较改为对 air_wall 节点组调用
IsInGroup("air_wall"),并移除冗余的 body is Node node 检查;同时将
scripts/items/world/RigidBodyWorldItemEntity.cs#L1259-L1263
的相同名称判断改为同一组判定,并更新对应关卡场景将空气墙节点加入 air_wall 组。

Comment on lines +718 to +736

// 撞墙检测:手动物理射线(freeze 刚体子节点的 Area2D 信号不可靠),
// 沿水平飞行方向检测前方墙体,命中非 GameActor 物理体则停止并销毁
if (_impactArmed && StopOnHit && CheckWallHit(_rigidBody.GlobalPosition, _throwHorizontalVelocity))
{
_inFlight = false;
_flightTimer = 0.0;
_impactArmed = false;
_rigidBody.LinearVelocity = Vector2.Zero;
try { _rigidBody.Set("freeze", true); } catch { }
RestoreRigidBodyCollision();
if (!_isDestroying)
{
_landingHideTimer = LandingHideDelay;
if (!IsDisposableCopy && IsThrowWeapon)
_inventoryReturnTimer = ThrowWeaponCooldown;
}
return;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

撞墙分支没有恢复阴影,也没有重置 _isDropping 喵。

请对比第 748-780 行的正常落地分支喵。那里第 765 行调用了 SetShadowVisible(true),第 751 行把 _isDropping 置 false 喵。

ApplyThrowImpulse 在第 563 行投掷时调用了 SetShadowVisible(false)。新增的撞墙分支停止飞行后没有把阴影恢复回来喵。物品会在墙边静止 LandingHideDelay 秒(默认 2 秒)且没有阴影,与正常落地的表现不一致喵。

另外第 719-720 行的注释也和实现对不上喵:注释写「命中非 GameActor 物理体则停止并销毁」,但 CheckWallHit 只认 AirWall,而且这个分支只是停止飞行并启动隐藏计时,并不会立即销毁喵。

🐛 建议的修复
-			// 撞墙检测:手动物理射线(freeze 刚体子节点的 Area2D 信号不可靠),
-			// 沿水平飞行方向检测前方墙体,命中非 GameActor 物理体则停止并销毁
+			// 撞墙检测:手动物理射线(freeze 刚体子节点的 Area2D 信号不可靠),
+			// 沿水平飞行方向检测前方空气墙,命中后停止飞行并进入落地隐藏流程
 			if (_impactArmed && StopOnHit && CheckWallHit(_rigidBody.GlobalPosition, _throwHorizontalVelocity))
 			{
 				_inFlight = false;
 				_flightTimer = 0.0;
 				_impactArmed = false;
+				_isDropping = false;
 				_rigidBody.LinearVelocity = Vector2.Zero;
 				try { _rigidBody.Set("freeze", true); } catch { }
 				RestoreRigidBodyCollision();
+				SetShadowVisible(true);
 				if (!_isDestroying)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 撞墙检测:手动物理射线(freeze 刚体子节点的 Area2D 信号不可靠),
// 沿水平飞行方向检测前方墙体,命中非 GameActor 物理体则停止并销毁
if (_impactArmed && StopOnHit && CheckWallHit(_rigidBody.GlobalPosition, _throwHorizontalVelocity))
{
_inFlight = false;
_flightTimer = 0.0;
_impactArmed = false;
_rigidBody.LinearVelocity = Vector2.Zero;
try { _rigidBody.Set("freeze", true); } catch { }
RestoreRigidBodyCollision();
if (!_isDestroying)
{
_landingHideTimer = LandingHideDelay;
if (!IsDisposableCopy && IsThrowWeapon)
_inventoryReturnTimer = ThrowWeaponCooldown;
}
return;
}
// 撞墙检测:手动物理射线(freeze 刚体子节点的 Area2D 信号不可靠),
// 沿水平飞行方向检测前方空气墙,命中后停止飞行并进入落地隐藏流程
if (_impactArmed && StopOnHit && CheckWallHit(_rigidBody.GlobalPosition, _throwHorizontalVelocity))
{
_inFlight = false;
_flightTimer = 0.0;
_impactArmed = false;
_isDropping = false;
_rigidBody.LinearVelocity = Vector2.Zero;
try { _rigidBody.Set("freeze", true); } catch { }
RestoreRigidBodyCollision();
SetShadowVisible(true);
if (!_isDestroying)
{
_landingHideTimer = LandingHideDelay;
if (!IsDisposableCopy && IsThrowWeapon)
_inventoryReturnTimer = ThrowWeaponCooldown;
}
return;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/items/world/RigidBodyWorldItemEntity.cs` around lines 718 - 736,
Update the wall-hit branch around CheckWallHit to reset _isDropping and call
SetShadowVisible(true), matching the normal landing branch before starting the
hide timer. Also revise the nearby comment to describe the actual AirWall-only
detection and stop-then-hide behavior rather than claiming all non-GameActor
bodies are immediately destroyed.

Comment thread scripts/ui/BuildCard.cs
[Export] public Label? NameLabel { get; set; }
[Export] public Label? BuildClassLabel { get; set; }
[Export] public Label? DescLabel { get; set; }
[Export] public RichTextLabel? DescLabel { get; set; }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Godot 4 RichTextLabel theme font size normal_font_size add_theme_font_size_override

💡 Result:

In Godot 4, you can modify the font size of a RichTextLabel programmatically using the add_theme_font_size_override method [1][2]. To change the default ("normal") font size, you use the "normal_font_size" theme property identifier [1][2]. Example code: $RichTextLabel.add_theme_font_size_override("normal_font_size", 24) RichTextLabel exposes several distinct theme font size overrides that you can target individually [2]: - normal_font_size [3][2] - bold_font_size [3][2] - italics_font_size [3][2] - bold_italics_font_size [2] - mono_font_size [3][2] If you want to apply a font size override that applies to text generally or temporarily within the text itself (rather than the label's base theme), you can use the push_font_size(font_size) method while building your RichTextLabel's text stack [3][4]. To remove a programmatic override and revert to the theme default, use remove_theme_font_size_override("normal_font_size").

Citations:


🏁 Script executed:

#!/bin/bash
set -e

echo "== files =="
git ls-files | rg '(^|/)BuildCard\.cs$|构筑卡牌描述模板机制\.md$|godotproject\.gd$|project\.godot$' || true

echo "== BuildCard outline/sections =="
if [ -f scripts/ui/BuildCard.cs ]; then
  wc -l scripts/ui/BuildCard.cs
  sed -n '1,150p' scripts/ui/BuildCard.cs
fi

echo "== search font_size usages in project =="
rg -n 'AddThemeFontSizeOverride|font_size|normal_font_size|BoldFont|ItalicFont|MonoFont' scripts/ui/BuildCard.cs . 2>/dev/null || true

Repository: Project-N-E-K-O/K.U.R.O

Length of output: 32279


🌐 Web query:

Godot Label theme font size property font_size AddThemeFontSizeOverride

💡 Result:

In Godot (specifically version 4.0 and later), font size is handled as a theme property on Control nodes, including the Label node [1][2]. Unlike older versions where font size was often embedded within the font resource itself, Godot 4 separates font size into an integer value defined by the node [2]. To programmatically override the font size for a Label or any Control node that supports it, use the add_theme_font_size_override method [3][4]. Usage: label_node.add_theme_font_size_override("font_size", 24) Key Details: 1. Method Name: The method is add_theme_font_size_override [5][6]. Note that some users may incorrectly attempt to use paths like "theme_override_font_sizes/font_size" [5][6]; the correct string name for the theme item is simply "font_size" [5]. 2. Alternative Approaches: For Label nodes specifically, you can also use a LabelSettings resource [7][2]. If a LabelSettings resource is assigned to a Label, it takes priority over standard theme overrides [7][6]. 3. Theme Items: The "font_size" property is a standard theme item for Label nodes [1][8][9]. You can check if a theme item exists or remove overrides using related methods like remove_theme_font_size_override or has_theme_font_size_override [10]. If your font size change is not appearing, ensure that you are not accidentally overriding it with a LabelSettings resource, which has higher priority than theme property overrides [7][6].

Citations:


Line 109 需要改用 RichTextLabel 的字号主题键喵。

DescLabel 已经是 RichTextLabel,不再用 Label 的 font_size 主题项,AddThemeFontSizeOverride("font_size", ...) 对描述文本不会生效喵。

🐛 建议改动(Line 109)
-            DescLabel?.AddThemeFontSizeOverride("font_size", Mathf.RoundToInt(12 * ratio));
+            DescLabel?.AddThemeFontSizeOverride("normal_font_size", Mathf.RoundToInt(12 * ratio));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ui/BuildCard.cs` at line 18, Update the theme font-size override for
DescLabel to use the RichTextLabel-specific theme key instead of Label’s
“font_size” key, while preserving the existing size value and override flow.

Comment thread scripts/ui/CoreHUD.cs
Comment on lines +59 to +65
float maxHeat = _boundMachineCore.MaxHeat;
float heat = _boundMachineCore.Heat;
float overflow = Mathf.Max(heat - maxHeat, 0f);
float factor = 1f + (maxHeat > 0f ? overflow / maxHeat : 0f);
var fillScale = HeatFillBar.Scale;
fillScale.X = _baseFillScaleX * factor;
HeatFillBar.Scale = fillScale;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

限制 HeatFillBar 的溢出缩放上限喵。

第 62 行没有将 factor 限制为 1.5,但第 57-58 行声明最大缩放为 1.5 喵。
Heat 超过 1.5 * MaxHeat 时,热量条会继续扩大,显示结果不符合该上限喵。
请限制溢出比例,或者更新注释以明确支持无上限缩放喵。

建议修复喵
-            float factor = 1f + (maxHeat > 0f ? overflow / maxHeat : 0f);
+            float factor = 1f + (maxHeat > 0f ? Mathf.Min(overflow / maxHeat, 0.5f) : 0f);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
float maxHeat = _boundMachineCore.MaxHeat;
float heat = _boundMachineCore.Heat;
float overflow = Mathf.Max(heat - maxHeat, 0f);
float factor = 1f + (maxHeat > 0f ? overflow / maxHeat : 0f);
var fillScale = HeatFillBar.Scale;
fillScale.X = _baseFillScaleX * factor;
HeatFillBar.Scale = fillScale;
float maxHeat = _boundMachineCore.MaxHeat;
float heat = _boundMachineCore.Heat;
float overflow = Mathf.Max(heat - maxHeat, 0f);
float factor = 1f + (maxHeat > 0f ? Mathf.Min(overflow / maxHeat, 0.5f) : 0f);
var fillScale = HeatFillBar.Scale;
fillScale.X = _baseFillScaleX * factor;
HeatFillBar.Scale = fillScale;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ui/CoreHUD.cs` around lines 59 - 65, 在 CoreHUD 中更新 factor 的计算,使
HeatFillBar 的最终缩放不超过已声明的 1.5 倍上限;对溢出比例或计算结果应用上限限制,并保留 MaxHeat 为零时的现有安全行为。

新增MachienHeatFlowImpactEffect
修复machineCoreEffect异常问题

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/builds/buildcore/MachineCoreEffect.cs (1)

106-113: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

在超频开启时也要钳制缩容后的 Heat 喵。

Line 112 只在 AllowHeatOverflowfalse 时限制 Heat 喵。
如果效果降低 MaxHeat 且超频已开启,现有 Heat 可以超过新的 MaxHeat + MaxOverflowHeat 喵。
随后 ApplyOverflowBuff 会把超出配置上限的热量转换为属性加成喵。
在更新 MaxHeat 后,始终使用 GetHeatCap() 钳制 Heat 喵。

建议修复喵
-            if (stat == HeatStat.MaxHeat && !AllowHeatOverflow && Heat > MaxHeat)
-                Heat = MaxHeat;
+            if (stat == HeatStat.MaxHeat)
+                Heat = Mathf.Min(Heat, GetHeatCap());
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/builds/buildcore/MachineCoreEffect.cs` around lines 106 - 113, Update
the Heat adjustment in the MaxHeat branch of SetStatValue so it always clamps
Heat after MaxHeat changes, including when AllowHeatOverflow is enabled. Compare
Heat against GetHeatCap() and cap it accordingly, preserving the existing
behavior when Heat is already within the effective limit.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@shaders/materials/fire_effect.gdshader`:
- Around line 74-76: 在计算 projected_uv 前更新 world_pos_3d.z 的保护逻辑,使其无论
cull_backface 状态如何,都丢弃绝对值接近零的深度值;保留现有背面剔除行为,并确保后续投影除法不会接收零或近零分母。
- Around line 1-2: 补充 fire_effect.gdshader 顶部许可归属注释,注明原作者 trisomie21、Shadertoy
转换来源及 Godot Shaders 转载信息,并明确该衍生着色器采用 CC BY-NC-SA 3.0;同时说明商业发布或闭源资产使用前需取得作者另行授权。

---

Outside diff comments:
In `@scripts/builds/buildcore/MachineCoreEffect.cs`:
- Around line 106-113: Update the Heat adjustment in the MaxHeat branch of
SetStatValue so it always clamps Heat after MaxHeat changes, including when
AllowHeatOverflow is enabled. Compare Heat against GetHeatCap() and cap it
accordingly, preserving the existing behavior when Heat is already within the
effective limit.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 56c5d992-ef83-4da1-9882-cbff02e193c7

📥 Commits

Reviewing files that changed from the base of the PR and between 4dfca91 and 1eabe58.

📒 Files selected for processing (9)
  • resources/builds/BuildMachine_A_010.tres
  • scenes/builds/machine/MachineHeatFlowImpactEffect.tscn
  • scenes/builds/machine/MachineHeatFlowVisual.tscn
  • scenes/managers/BuildSelectionManager.tscn
  • scripts/builds/buildcore/MachineCoreEffect.cs
  • scripts/builds/machine/MachineBurstThrustEffect.cs
  • scripts/builds/machine/MachineHeatFlowImpactEffect.cs
  • scripts/effects/DotBurnEffect.cs
  • shaders/materials/fire_effect.gdshader
💤 Files with no reviewable changes (1)
  • scenes/managers/BuildSelectionManager.tscn
🚧 Files skipped from review as they are similar to previous changes (4)
  • scenes/builds/machine/MachineHeatFlowImpactEffect.tscn
  • resources/builds/BuildMachine_A_010.tres
  • scripts/builds/machine/MachineBurstThrustEffect.cs
  • scripts/effects/DotBurnEffect.cs

Comment on lines +1 to +2
// Adopted from https://godotshaders.com/shader/ball-of-fire/ by https://godotshaders.com/author/ahaugas/
//

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

确认 Godot Shaders 的 “Ball Of Fire” 和原始 Shadertoy “lsf3RH” 的作者、明确许可证,以及 CC BY-NC-SA 3.0 是否允许本项目的预期分发方式。

💡 Result:

关于 Godot Shaders 上的“Ball Of Fire”及原始 Shadertoy 项目“lsf3RH”的作者与许可信息如下: 1. 作者与来源 Godot Shaders 上的“Ball Of Fire”项目由用户 ahaugas 发布,明确标注其为 Shadertoy 项目的移植版本 [1][2]。原始 Shadertoy 项目“lsf3RH”的作者为 trisomie21 [3][4]。 2. 许可协议 Shadertoy 平台上的内容默认受知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版(CC BY-NC-SA 3.0)许可协议保护 [1][2][5]。Godot Shaders 平台亦声明其转载的 Shadertoy 移植项目同样受该协议约束,除非作者另有说明 [1][2]。 3. CC BY-NC-SA 3.0 对分发的限制 CC BY-NC-SA 3.0 协议包含三个核心限制,严重影响商业分发: 非商业性(NonCommercial, NC):禁止将作品用于任何主要以商业优势或金钱补偿为目的的使用 [6][7][8]。这意味着如果您的项目通过销售、内置广告、付费订阅或任何旨在获取商业利润的模式进行分发,则该协议不允许此类使用 [7][8]。 相同方式共享(ShareAlike, SA):如果您对该代码进行了修改(衍生作品)并将其公开分发,则您必须使用相同或兼容的协议(如 CC BY-NC-SA 3.0 或更高版本的协议)来许可您的贡献部分 [7][8][9]。 署名(Attribution, BY):您必须给出适当的信用,提供协议链接,并指示是否进行了更改 [7][8]。 总结:如果您计划的分发方式涉及商业获利(例如出售包含该着色器的软件),则 CC BY-NC-SA 3.0 协议通常不允许此类行为 [7][8]。此外,受“相同方式共享”条款限制,若您将其集成至软件中,可能需确保您的软件或该部分代码遵循开源共享要求 [7][8]。建议在进行商业分发前,咨询法律专业人士或联系原始作者获取明确的书面授权。

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="shaders/materials/fire_effect.gdshader"
if [ -f "$file" ]; then
  echo "== file header =="
  sed -n '1,30p' "$file"
  echo
  echo "== license mentions in repository =="
  rg -n "CC BY-NC-SA|CC-BY-NC-SA|ShareAlike|BY-NC-SA|license|licence|LICENSE|licen" . \
    -g '!*/.git*' -g '!*bin*' -g '!*obj*' | head -200
else
  echo "missing $file"
fi

Repository: Project-N-E-K-O/K.U.R.O

Length of output: 8785


补全校重着色器的许可归属喵。

fire_effect.gdshader 标注来自 Godot Shaders,但 Godot Shaders 将该 Shadertoy 转换作品默认按 CC BY-NC-SA 3.0 处理喵。当前仓库是 MIT,不能覆盖这一衍生素材的非商业性限制或 ShareAlike 要求喵。非商用发布前,补署原作者 trisomie21 与转换来源,并明确该文件受 CC BY-NC-SA 3.0 约束喵;若计划商业或使用闭源资产,必须先取得作者另行授权喵。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shaders/materials/fire_effect.gdshader` around lines 1 - 2, 补充
fire_effect.gdshader 顶部许可归属注释,注明原作者 trisomie21、Shadertoy 转换来源及 Godot Shaders
转载信息,并明确该衍生着色器采用 CC BY-NC-SA 3.0;同时说明商业发布或闭源资产使用前需取得作者另行授权。

Comment on lines +74 to +76
if (cull_backface && world_pos_3d.z <= 0.0) discard;

vec2 projected_uv = (world_pos_3d.xy / world_pos_3d.z) - offset + 0.5;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

在投影前保护零深度除法喵。

cull_backfacefalse 且平面接近边缘朝向时,world_pos_3d.z 可以为零喵。
Line 76 会执行零除,并使 projected_uv 产生 NaN 或无穷值喵。
这会导致效果闪烁、缺块或错误像素喵。
在执行投影除法前,始终丢弃接近零的深度值喵。

建议修复喵
-    if (cull_backface && world_pos_3d.z <= 0.0) discard;
+    if (abs(world_pos_3d.z) <= 0.0001) discard;
+    if (cull_backface && world_pos_3d.z < 0.0) discard;
 
     vec2 projected_uv = (world_pos_3d.xy / world_pos_3d.z) - offset + 0.5;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (cull_backface && world_pos_3d.z <= 0.0) discard;
vec2 projected_uv = (world_pos_3d.xy / world_pos_3d.z) - offset + 0.5;
if (abs(world_pos_3d.z) <= 0.0001) discard;
if (cull_backface && world_pos_3d.z < 0.0) discard;
vec2 projected_uv = (world_pos_3d.xy / world_pos_3d.z) - offset + 0.5;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shaders/materials/fire_effect.gdshader` around lines 74 - 76, 在计算
projected_uv 前更新 world_pos_3d.z 的保护逻辑,使其无论 cull_backface
状态如何,都丢弃绝对值接近零的深度值;保留现有背面剔除行为,并确保后续投影除法不会接收零或近零分母。

修复B005造成的异常伤害问题
新增B007以及相关特效
优化B004、006伤害特效

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
scenes/builds/machine/MachineFlameRing.tscn (1)

256-374: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

建议给各火苗设置不同的起始帧喵。

这 20 个 AnimatedSprite2D 共用同一个 SpriteFrames,而且全部 autoplay = "default"。它们会在同一帧播放同一张图,整圈火苗会同步闪烁喵。给每个节点加一个不同的 frame 初值就能打散节奏,成本很低哦~

♻️ 示例改法
 [node name="AnimatedSprite2D11" type="AnimatedSprite2D" parent="Sprite2D2"]
 position = Vector2(-74.28571, -228.57143)
 scale = Vector2(0.4, 0.4)
 sprite_frames = SubResource("SpriteFrames_3gppx")
 autoplay = "default"
+frame = 7
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scenes/builds/machine/MachineFlameRing.tscn` around lines 256 - 374, 为
AnimatedSprite2D 至 AnimatedSprite2D20 的每个 AnimatedSprite2D 节点设置不同的初始 frame
值,以打散共用 SpriteFrames 和 autoplay="default" 导致的同步闪烁;保留现有位置、缩放及播放配置不变。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/fx/MachineFlameRingEffect.cs`:
- Around line 80-100: Constrain the capsule aspect ratio to at most 1 in both
affected sites: scripts/fx/MachineFlameRingEffect.cs lines 80-100 and
scripts/builds/machine/MachineHeatFlowImpactEffect.cs lines 106-121. Update the
DamageAreaAspectY export range and use the clamped aspect consistently when
calculating Radius and related capsule dimensions in MachineFlameRingEffect and
MachineHeatFlowImpactEffect, including the sibling calculation at line 154.

In `@shaders/materials/fire_cartoon.gdshader`:
- Around line 150-153: Update bounds_mask in the shader’s UV safety-margin block
to validate the original uv coordinates rather than uv_segura, so increasing
margem_seguranca expands sampling without shrinking the visible region to the
center. Preserve the uv_segura calculation for texture sampling and retain the
existing [0,1] bounds behavior.

In `@shaders/materials/fire_ring.gdshader`:
- Around line 44-58: Prevent projection from dividing by non-positive
world_pos_3d.z regardless of cull_backface: update
shaders/materials/fire_ring.gdshader lines 44-58 and
shaders/materials/fire_cartoon.gdshader lines 138-148 to unconditionally discard
z <= 0.0 before projection, or clamp the divisor to a small positive value,
keeping both shaders’ projection behavior consistent.

In `@shaders/materials/ring_of_shield.gdshader`:
- Around line 38-47: 在 ring shield shader 的 border_factor 计算中,先将其限制为不小于 0,再传入
pow,确保边角区域不会对负底数求幂并产生 NaN;保留现有 border_energy 和中心衰减逻辑不变。

---

Nitpick comments:
In `@scenes/builds/machine/MachineFlameRing.tscn`:
- Around line 256-374: 为 AnimatedSprite2D 至 AnimatedSprite2D20 的每个
AnimatedSprite2D 节点设置不同的初始 frame 值,以打散共用 SpriteFrames 和 autoplay="default"
导致的同步闪烁;保留现有位置、缩放及播放配置不变。
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 55dec9b0-4e48-4c06-9340-b8b153e2ad80

📥 Commits

Reviewing files that changed from the base of the PR and between 8eccd4c and 6eb8177.

⛔ Files ignored due to path filters (4)
  • assets/effect/AttackEffect/ringA/ring.png is excluded by !**/*.png
  • assets/effect/AttackEffect/ringA/ringB.png is excluded by !**/*.png
  • assets/effect/AttackEffect/ringA/ringB_1.png is excluded by !**/*.png
  • assets/effect/AttackEffect/ringA/ringB_2.png is excluded by !**/*.png
📒 Files selected for processing (11)
  • scenes/builds/MachineCore.tscn
  • scenes/builds/machine/MachineFlameRing.tscn
  • scenes/builds/machine/MachineHeatFlowImpactEffect.tscn
  • scenes/builds/machine/MachineHeatFlowVisual.tscn
  • scenes/managers/BuildSelectionManager.tscn
  • scripts/builds/machine/MachineHeatFlowImpactEffect.cs
  • scripts/fx/MachineFlameRingEffect.cs
  • shaders/materials/fire_cartoon.gdshader
  • shaders/materials/fire_ring.gdshader
  • shaders/materials/ring_of_power.gdshader
  • shaders/materials/ring_of_shield.gdshader
💤 Files with no reviewable changes (2)
  • scenes/managers/BuildSelectionManager.tscn
  • scenes/builds/MachineCore.tscn
🚧 Files skipped from review as they are similar to previous changes (2)
  • scenes/builds/machine/MachineHeatFlowImpactEffect.tscn
  • scenes/builds/machine/MachineHeatFlowVisual.tscn

Comment on lines +80 to +100
// 持续扩散:0 → MaxRadius。
// 水平胶囊:Radius = 上下半宽(短轴),Height = 总长(Godot 4 中 CapsuleShape2D.Height
// 是含两端半球的整体长度,直接 = 左右直径 2r)。
// 总长 = Height = 2r,总高 = 2×Radius = 2r×aspect
float t = Mathf.Clamp(_elapsed / ExpandDuration, 0f, 1f);
_currentRadius = MaxRadius * t;
if (_contactShape != null)
{
_contactShape.Radius = _currentRadius * DamageAreaAspectY;
_contactShape.Height = 2f * _currentRadius;
}

// 视觉环同步扩张:Scale = 基准缩放 × 当前半径 / 基准半径
if (_visualSprite != null && VisualBaseRadius > 0f)
{
float f = Mathf.Max(_currentRadius / VisualBaseRadius, 0.001f);
_visualSprite.Scale = _baseSpriteScale * f;
}

QueueRedraw();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

水平胶囊换算未约束 DamageAreaAspectY <= 1 喵。 两个文件用同一套换算:Radius = r * DamageAreaAspectYHeight = 2 * r。Godot 的 CapsuleShape2D 强制 Height >= 2 * Radius,所以 aspect 大于 1 时引擎会抬高 Height,判定区域比配置的范围更大且退化为圆。两处的 Export 范围都是 0.1,2,0.05,允许出现该取值喵。

  • scripts/fx/MachineFlameRingEffect.cs#L80-L100:把 DamageAreaAspectY 的 Export 范围改为 0.1,1,0.05,或在第 88 行用 Mathf.Min(DamageAreaAspectY, 1f) 钳制后再计算 Radius
  • scripts/builds/machine/MachineHeatFlowImpactEffect.cs#L106-L121:同样收紧第 28 行的 Export 范围,并在第 112 行和第 154 行使用钳制后的 aspect 值。
📍 Affects 2 files
  • scripts/fx/MachineFlameRingEffect.cs#L80-L100 (this comment)
  • scripts/builds/machine/MachineHeatFlowImpactEffect.cs#L106-L121
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/fx/MachineFlameRingEffect.cs` around lines 80 - 100, Constrain the
capsule aspect ratio to at most 1 in both affected sites:
scripts/fx/MachineFlameRingEffect.cs lines 80-100 and
scripts/builds/machine/MachineHeatFlowImpactEffect.cs lines 106-121. Update the
DamageAreaAspectY export range and use the clamped aspect consistently when
calculating Radius and related capsule dimensions in MachineFlameRingEffect and
MachineHeatFlowImpactEffect, including the sibling calculation at line 154.

Comment on lines +150 to +153
// ── 1. 安全边距:UV 向外扩张,让火焰贴边不被精灵边界硬切 ──
vec2 uv_segura = (uv - 0.5) * (1.0 + margem_seguranca * 2.0) + 0.5;
// 超出 [0,1] 的像素直接透明(bounds_mask = 0)
float bounds_mask = step(0.0, uv_segura.x) * step(uv_segura.x, 1.0) * step(0.0, uv_segura.y) * step(uv_segura.y, 1.0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

margem_seguranca 的实现和注释相反喵。

注释说这个参数让 UV 向外扩张,用来防止火焰在精灵边缘被硬切。但代码先扩张 UV 得到 uv_segura,然后又用同一个 uv_segura 去做 [0,1] 边界裁剪。结果是有效区域被压缩成中心的 1/(1+2*margem_seguranca)margem_seguranca 越大可见范围越小喵。

scenes/builds/machine/MachineFlameRing.tscnmargem_seguranca 设为 4.0,按此逻辑只有中心约 11% 的区域会被绘制。请确认这是刻意的取舍。如果目标是防止硬切,bounds_mask 应该基于原始 uv 而不是 uv_segura 喵~

🐛 若目标是防止硬切的改法
     vec2 uv_segura = (uv - 0.5) * (1.0 + margem_seguranca * 2.0) + 0.5;
-    // 超出 [0,1] 的像素直接透明(bounds_mask = 0)
-    float bounds_mask = step(0.0, uv_segura.x) * step(uv_segura.x, 1.0) * step(0.0, uv_segura.y) * step(uv_segura.y, 1.0);
+    // 精灵自身范围内才绘制(用原始 uv 判断,扩张仅用于噪声/形状采样)
+    float bounds_mask = step(0.0, uv.x) * step(uv.x, 1.0) * step(0.0, uv.y) * step(uv.y, 1.0);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// ── 1. 安全边距:UV 向外扩张,让火焰贴边不被精灵边界硬切 ──
vec2 uv_segura = (uv - 0.5) * (1.0 + margem_seguranca * 2.0) + 0.5;
// 超出 [0,1] 的像素直接透明(bounds_mask = 0
float bounds_mask = step(0.0, uv_segura.x) * step(uv_segura.x, 1.0) * step(0.0, uv_segura.y) * step(uv_segura.y, 1.0);
// ── 1. 安全边距:UV 向外扩张,让火焰贴边不被精灵边界硬切 ──
vec2 uv_segura = (uv - 0.5) * (1.0 + margem_seguranca * 2.0) + 0.5;
// 精灵自身范围内才绘制(用原始 uv 判断,扩张仅用于噪声/形状采样
float bounds_mask = step(0.0, uv.x) * step(uv.x, 1.0) * step(0.0, uv.y) * step(uv.y, 1.0);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shaders/materials/fire_cartoon.gdshader` around lines 150 - 153, Update
bounds_mask in the shader’s UV safety-margin block to validate the original uv
coordinates rather than uv_segura, so increasing margem_seguranca expands
sampling without shrinking the visible region to the center. Preserve the
uv_segura calculation for texture sampling and retain the existing [0,1] bounds
behavior.

Comment on lines +44 to +58
void fragment() {
// ── 伪 3D:背面剔除 + 透视投影出当前片元对应的 UV ──
if (cull_backface && world_pos_3d.z <= 0.0) discard;

vec2 projected_uv = (world_pos_3d.xy / world_pos_3d.z) - proj_offset + 0.5;
if (projected_uv.x < 0.0 || projected_uv.x > 1.0 || projected_uv.y < 0.0 || projected_uv.y > 1.0)
discard;

// ── 噪声扭曲(fire_ring 原逻辑,采样改在投影后的 UV 上)──
float noise1_value = texture(noise1, projected_uv + TIME * 0.15).r - 0.5;
float noise2_value = texture(noise2, projected_uv - TIME * 0.25).r - 0.5;
float mixed_noise = noise1_value * noise2_value * influence;

vec2 offset = vec2(0.02, 0.15) * mixed_noise;
COLOR = texture(TEXTURE, projected_uv + offset); // 精灵纹理扭曲采样(形状)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

伪 3D 投影的除法只在 cull_backfacetrue 时才安全喵。 两个着色器共用同一段投影代码:先判断 if (cull_backface && world_pos_3d.z <= 0.0) discard;,再执行 world_pos_3d.xy / world_pos_3d.z。守卫依赖 uniform 开关,关闭后 z 为 0 或负值时会得到 NaN,随后的 projected_uv 越界比较对 NaN 全部为假,片元不会被丢弃喵。当前场景材质都设为 true,但 uniform 可在编辑器里关掉~

  • shaders/materials/fire_ring.gdshader#L44-L58:把第 46 行改为无条件丢弃 z <= 0.0 的片元,或在第 48 行使用 max(world_pos_3d.z, 1e-5) 作除数。
  • shaders/materials/fire_cartoon.gdshader#L138-L148:对第 140 行和第 142 行做同样处理,保持两个着色器的投影行为一致。
📍 Affects 2 files
  • shaders/materials/fire_ring.gdshader#L44-L58 (this comment)
  • shaders/materials/fire_cartoon.gdshader#L138-L148
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shaders/materials/fire_ring.gdshader` around lines 44 - 58, Prevent
projection from dividing by non-positive world_pos_3d.z regardless of
cull_backface: update shaders/materials/fire_ring.gdshader lines 44-58 and
shaders/materials/fire_cartoon.gdshader lines 138-148 to unconditionally discard
z <= 0.0 before projection, or clamp the divisor to a small positive value,
keeping both shaders’ projection behavior consistent.

Comment on lines +38 to +47
// how close to frontier is
float border_factor = 1.0 - distance(2.0*(UV - center), center_uv);
// 呼吸:以 border_energy_offset 为基准,正弦在 0~1 间波动(关闭时保持原值,不改变原有行为)
float border_energy = border_energy_offset;
if (breath_active)
{
float wave = 0.5 + 0.5 * sin(TIME * breath_speed * TAU);
border_energy = mix(border_energy_offset, wave, breath_strength);
}
border_factor = pow(border_factor, border_energy*50.0); // speeding up center fading

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

pow 的底数可能为负,会产生 NaN 喵。

第 39 行 border_factor = 1.0 - distance(2.0*(UV - center), center_uv)center_uv 是单位向量,2.0*(UV - center) 的长度最大约 1.414,两者距离最大约 2.414。因此 border_factor 在精灵四角附近会变成负值喵。

GLSL 中 pow(x, y)x < 0 时结果未定义,通常返回 NaN。第 58 行 COLOR.a 乘上 NaN 后仍是 NaN,即使 is 为 0 也无法把它归零,可能出现黑块或闪烁喵。请先 clamp 再做 pow

🐛 建议修复
-	float border_factor = 1.0 - distance(2.0*(UV - center), center_uv);
+	float border_factor = clamp(1.0 - distance(2.0*(UV - center), center_uv), 0.0, 1.0);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// how close to frontier is
float border_factor = 1.0 - distance(2.0*(UV - center), center_uv);
// 呼吸:以 border_energy_offset 为基准,正弦在 0~1 间波动(关闭时保持原值,不改变原有行为)
float border_energy = border_energy_offset;
if (breath_active)
{
float wave = 0.5 + 0.5 * sin(TIME * breath_speed * TAU);
border_energy = mix(border_energy_offset, wave, breath_strength);
}
border_factor = pow(border_factor, border_energy*50.0); // speeding up center fading
// how close to frontier is
float border_factor = clamp(1.0 - distance(2.0*(UV - center), center_uv), 0.0, 1.0);
// 呼吸:以 border_energy_offset 为基准,正弦在 0~1 间波动(关闭时保持原值,不改变原有行为)
float border_energy = border_energy_offset;
if (breath_active)
{
float wave = 0.5 + 0.5 * sin(TIME * breath_speed * TAU);
border_energy = mix(border_energy_offset, wave, breath_strength);
}
border_factor = pow(border_factor, border_energy*50.0); // speeding up center fading
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shaders/materials/ring_of_shield.gdshader` around lines 38 - 47, 在 ring
shield shader 的 border_factor 计算中,先将其限制为不小于 0,再传入 pow,确保边角区域不会对负底数求幂并产生 NaN;保留现有
border_energy 和中心衰减逻辑不变。

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@resources/items/Furniture_C_FoodCartA.tres`:
- Line 8: 同步这些 Texture2D 外部资源的 UID,确保与同路径场景及资源中的 UID 一致;检查并更新
resources/items/Furniture_C_FoodCartA.tres:8、Furniture_C_TableRoundC.tres:8、Furniture_D_PrinterMachineA.tres:8、Furniture_D_TableOfficeB_rwd.tres:8、Furniture_D_WaterMachineA.tres:8、Furniture_D_WhiteBoardA.tres:8、Weapon_Brawl_MechGlove.tres:5、Weapon_Brawl_RiotGlove.tres:5、Weapon_Slash_BunnySword.tres:5,并搜索其他
.tscn/.tres 引用同步相同资源的 UID。

In `@scenes/actors/characters/Enemy_B2_fat02.tscn`:
- Line 4: 确认 Enemy_NormalDrops 与 Enemy_C_EliteDrops 的物品数量及 GlobalDropChance
是否符合游戏平衡,并核实 C/D 区新增通用普通掉落绑定是否为设计预期;若非预期,恢复对应敌人的原掉落表或调整掉落配置。涉及
scenes/actors/characters/Enemy_B2_fat02.tscn(4-4、81-81)、Enemy_C1_waiterA.tscn(5-5、78-78)、Enemy_C1_waiterB.tscn(11-11、106-106)、Enemy_C2_waiterA02.tscn(5-5、71-71)、Enemy_D1_corpDoneA.tscn(4-4、79-79)和
Enemy_D1_corpDoneB.tscn(6-6、90-90);逐一确认这些资源绑定与精英掉落概率,非预期位置需要直接修正,预期位置无需改动。
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2433311b-d0e7-4d73-bda4-a3b98bc2bad8

📥 Commits

Reviewing files that changed from the base of the PR and between 6eb8177 and ce1e9f6.

📒 Files selected for processing (93)
  • dialogic/styles/textbubble_A.tres
  • resources/builds/BuildMachine_A_001.tres
  • resources/builds/BuildMachine_A_002.tres
  • resources/builds/BuildMachine_A_003.tres
  • resources/builds/BuildMachine_A_004.tres
  • resources/builds/BuildMachine_A_005.tres
  • resources/builds/BuildMachine_A_006.tres
  • resources/builds/BuildMachine_A_007.tres
  • resources/builds/BuildMachine_A_008.tres
  • resources/builds/BuildMachine_A_009.tres
  • resources/builds/BuildMachine_A_010.tres
  • resources/builds/BuildMachine_B_001.tres
  • resources/builds/BuildMachine_B_002.tres
  • resources/builds/BuildMachine_B_003.tres
  • resources/builds/BuildMachine_B_004.tres
  • resources/builds/BuildMachine_B_005.tres
  • resources/builds/BuildMachine_B_006.tres
  • resources/cutscene/B_begin_intro.tres
  • resources/cutscene/C_begin_intro.tres
  • resources/cutscene/D_begin_intro.tres
  • resources/cutscene/D_end_intro.tres
  • resources/items/Furniture_A_ChairOfficeB.tres
  • resources/items/Furniture_A_CubeA.tres
  • resources/items/Furniture_B_CautionTape_fwd.tres
  • resources/items/Furniture_B_CautionTape_side.tres
  • resources/items/Furniture_B_ChairA.tres
  • resources/items/Furniture_B_ChairA_fwd.tres
  • resources/items/Furniture_B_CoffeeMachineA.tres
  • resources/items/Furniture_B_CounterA.tres
  • resources/items/Furniture_B_CounterB.tres
  • resources/items/Furniture_B_GarbageCanA.tres
  • resources/items/Furniture_B_LuggageCartA.tres
  • resources/items/Furniture_B_PlantA.tres
  • resources/items/Furniture_B_SofaA.tres
  • resources/items/Furniture_B_SofaA_fwd.tres
  • resources/items/Furniture_B_SofaA_rwd.tres
  • resources/items/Furniture_B_TableRoundA.tres
  • resources/items/Furniture_B_TableRoundB.tres
  • resources/items/Furniture_B_VendingMachineA.tres
  • resources/items/Furniture_C_ChairB.tres
  • resources/items/Furniture_C_ChairB_fwd.tres
  • resources/items/Furniture_C_FoodCartA.tres
  • resources/items/Furniture_C_TableRoundC.tres
  • resources/items/Furniture_C_TableSquareA.tres
  • resources/items/Furniture_D_PrinterMachineA.tres
  • resources/items/Furniture_D_TableOfficeB_rwd.tres
  • resources/items/Furniture_D_WaterMachineA.tres
  • resources/items/Furniture_D_WhiteBoardA.tres
  • resources/items/Weapon_Brawl_MechGlove.tres
  • resources/items/Weapon_Brawl_RiotGlove.tres
  • resources/items/Weapon_Slash_BunnySword.tres
  • resources/items/Weapon_Slash_ViolinBow.tres
  • resources/items/Weapon_Throw_Briefcase.tres
  • resources/items/Weapon_Throw_GravityGrenade.tres
  • resources/items/Weapon_Throw_MetalSpike.tres
  • resources/items/Weapon_Throw_SmokeGrenade.tres
  • resources/items/skills/WeaponSkill_Brawl_DiscoBall.tres
  • resources/items/skills/WeaponSkill_Brawl_MechGlove.tres
  • resources/items/skills/WeaponSkill_Brawl_RiotBracer.tres
  • resources/items/skills/WeaponSkill_Brawl_RiotGlove.tres
  • resources/items/skills/WeaponSkill_Slash_Baguette.tres
  • resources/items/skills/WeaponSkill_Slash_BarrierGate.tres
  • resources/items/skills/WeaponSkill_Slash_BunnySword.tres
  • resources/items/skills/WeaponSkill_Slash_ExpandBaton.tres
  • resources/items/skills/WeaponSkill_Slash_ViolinBow.tres
  • resources/items/skills/WeaponSkill_Stab_Corkscrew.tres
  • resources/items/skills/WeaponSkill_Stab_Drill.tres
  • resources/items/skills/WeaponSkill_Stab_Umbrella.tres
  • resources/loot/Enemy_B_EliteDrops.tres
  • resources/loot/Enemy_B_NormalDrops.tres
  • resources/loot/Enemy_C_EliteDrops.tres
  • resources/loot/Enemy_C_NormalDrops.tres
  • resources/loot/Enemy_EliteDrops.tres
  • resources/loot/Enemy_NormalDrops.tres
  • resources/loot/Enemy_Normal_NormalDrops.tres
  • resources/loot/Enemy_SpecialDrops.tres
  • scenes/Stage_2.tscn
  • scenes/Stage_3.tscn
  • scenes/actors/characters/Enemy_B1_fat.tscn
  • scenes/actors/characters/Enemy_B1_thin.tscn
  • scenes/actors/characters/Enemy_B2_fat02.tscn
  • scenes/actors/characters/Enemy_C1_waiterA.tscn
  • scenes/actors/characters/Enemy_C1_waiterB.tscn
  • scenes/actors/characters/Enemy_C2_waiterA02.tscn
  • scenes/actors/characters/Enemy_D1_corpDoneA.tscn
  • scenes/actors/characters/Enemy_D1_corpDoneB.tscn
  • scenes/actors/characters/Enemy_D1_netAdmin.tscn
  • scenes/actors/characters/Enemy_D1_printerMachine.tscn
  • scenes/actors/characters/Enemy_Normal_guard1.tscn
  • scenes/actors/characters/Enemy_Normal_guard2.tscn
  • scenes/actors/characters/Enemy_Normal_guard3.tscn
  • scenes/levels/B_begin.tscn
  • scenes/managers/BuildSelectionManager.tscn
🚧 Files skipped from review as they are similar to previous changes (16)
  • resources/items/skills/WeaponSkill_Stab_Drill.tres
  • resources/builds/BuildMachine_B_002.tres
  • resources/items/skills/WeaponSkill_Brawl_RiotBracer.tres
  • resources/builds/BuildMachine_A_004.tres
  • resources/builds/BuildMachine_B_001.tres
  • resources/builds/BuildMachine_A_009.tres
  • resources/builds/BuildMachine_B_003.tres
  • resources/builds/BuildMachine_B_005.tres
  • resources/builds/BuildMachine_A_005.tres
  • resources/items/Weapon_Throw_Briefcase.tres
  • resources/builds/BuildMachine_A_006.tres
  • resources/builds/BuildMachine_A_008.tres
  • resources/builds/BuildMachine_B_006.tres
  • resources/builds/BuildMachine_A_010.tres
  • resources/builds/BuildMachine_B_004.tres
  • resources/builds/BuildMachine_A_002.tres

[ext_resource type="PackedScene" uid="uid://ciwlpetibguab" path="res://shaders/destroy_somke.tscn" id="4_1ch32"]
[ext_resource type="PackedScene" uid="uid://cmh3bnabinwi0" path="res://resources/effects/CameraShakeEffect.tscn" id="5_p8p0i"]
[ext_resource type="Texture2D" uid="uid://b3ipocumrfmc3" path="res://assets/furnitures/hotel_scene3/FoodCartA.png" id="6_oqybt"]
[ext_resource type="Texture2D" uid="uid://12j10fuh5jy7" path="res://assets/furnitures/hotel_scene3/FoodCartA.png" id="6_oqybt"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from collections import defaultdict
from pathlib import Path
import re

pattern = re.compile(
    r'\[ext_resource type="Texture2D" uid="([^"]+)" path="([^"]+)"'
)
references = defaultdict(list)

for file_path in Path(".").rglob("*"):
    if not file_path.is_file() or file_path.suffix not in {".tres", ".tscn"}:
        continue
    try:
        text = file_path.read_text(encoding="utf-8")
    except (UnicodeDecodeError, OSError):
        continue

    for uid, asset_path in pattern.findall(text):
        references[asset_path].append((uid, str(file_path)))

for asset_path, entries in sorted(references.items()):
    uids = {uid for uid, _ in entries}
    if len(uids) > 1:
        print(asset_path)
        for uid, file_path in entries:
            print(f"  {uid}  {file_path}")
PY

Repository: Project-N-E-K-O/K.U.R.O

Length of output: 6758


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re

files = [
    "resources/items/Furniture_C_FoodCartA.tres",
    "resources/items/Furniture_C_TableRoundC.tres",
    "resources/items/Furniture_D_PrinterMachineA.tres",
    "resources/items/Furniture_D_TableOfficeB_rwd.tres",
    "resources/items/Furniture_D_WaterMachineA.tres",
    "resources/items/Furniture_D_WhiteBoardA.tres",
    "resources/items/Weapon_Brawl_MechGlove.tres",
    "resources/items/Weapon_Brawl_RiotGlove.tres",
    "resources/items/Weapon_Slash_BunnySword.tres",
]

pattern = re.compile(r'\[ext_resource type="Texture2D" uid="([^"]+)" path="([^"]+)" id="([^"]+)"\]')

for file_path in files:
    text = Path(file_path).read_text(encoding="utf-8", errors="replace")
    for uid, path, eid in pattern.findall(text):
        candidates = []
        for p in Path(".").rglob("*.tscn"):
            try:
                s = p.read_text(encoding="utf-8", errors="replace")
            except Exception:
                continue
            for suid, spath, seid in pattern.findall(s):
                if spath == path and seid != eid:
                    candidates.append((uid, spath, eid, suid, seid, p))
        print(f"{file_path}: {uid} {path} id={eid}")
        for cu, sp, ce, su, se, p in candidates:
            print(f"  SCENE MATCH: {p}: {cu} {sp} id={ce}")

# Also list all entries for listed paths so the canonical UID does not depend on the current patch only.
for path in [
    "res://assets/furnitures/hotel_scene3/FoodCartA.png",
    "res://assets/furnitures/hotel_scene3/TableRoundC.png",
    "res://assets/furnitures/hotel_scene4/PrinterMachineA.png",
    "res://assets/furnitures/hotel_scene4/TableOfficeB_rwd.png",
    "res://assets/furnitures/hotel_scene4/WaterMachineA.png",
    "res://assets/furnitures/hotel_scene4/WhiteBoardA.png",
    "res://assets/weapons/机械冲撞臂.png",
    "res://assets/weapons/镇暴拳套.png",
    "res://assets/weapons/光剑.png",
]:
    matches = []
    for p in Path(".").rglob("*.tscn"):
        try:
            s = p.read_text(encoding="utf-8", errors="replace")
        except Exception:
            continue
        matches.extend(pattern.findall(s))
    print(f"PATH {path}: {[e[:3] for e in matches]}")
PY

Repository: Project-N-E-K-O/K.U.R.O

Length of output: 50380


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re

files = [
    "resources/items/Furniture_C_FoodCartA.tres",
    "resources/items/Furniture_C_TableRoundC.tres",
    "resources/items/Furniture_D_PrinterMachineA.tres",
    "resources/items/Furniture_D_TableOfficeB_rwd.tres",
    "resources/items/Furniture_D_WaterMachineA.tres",
    "resources/items/Furniture_D_WhiteBoardA.tres",
    "resources/items/Weapon_Brawl_MechGlove.tres",
    "resources/items/Weapon_Brawl_RiotGlove.tres",
    "resources/items/Weapon_Slash_BunnySword.tres",
]

paths = [
    "res://assets/furnitures/hotel_scene3/FoodCartA.png",
    "res://assets/furnitures/hotel_scene3/TableRoundC.png",
    "res://assets/furnitures/hotel_scene4/PrinterMachineA.png",
    "res://assets/furnitures/hotel_scene4/TableOfficeB_rwd.png",
    "res://assets/furnitures/hotel_scene4/WaterMachineA.png",
    "res://assets/furnitures/hotel_scene4/WhiteBoardA.png",
    "res://assets/weapons/机械冲撞臂.png",
    "res://assets/weapons/镇暴拳套.png",
    "res://assets/weapons/光剑.png",
]

pattern = re.compile(r'\[ext_resource type="Texture2D" uid="([^"]+)" path="([^"]+)" id="([^"]+)"\]')
tres_by_path = {}
tscn_by_path = {}

for file_path in files:
    text = Path(file_path).read_text(encoding="utf-8", errors="replace")
    for uid, path, eid in pattern.findall(text):
        tres_by_path[path] = (uid, eid, file_path)

for tscn in Path(".").rglob("*.tscn"):
    text = tscn.read_text(encoding="utf-8", errors="replace")
    for uid, path, eid in pattern.findall(text):
        if path in paths:
            tscn_by_path.setdefault(path, []).append((uid, eid, tscn))

matches = []
for path in paths:
    tres = tres_by_path.get(path)
    scenes = tscn_by_path.get(path, [])
    if not tres:
        continue
    matching_scenes = [s for s in scenes if s[0] == tres[0]]
    differing_scenes = [s for s in scenes if s[0] != tres[0]]
    matches.append((path, tres, matching_scenes, differing_scenes))

print("path; tres_uid; tres_id; scene_uid=scene_id matching_count; differing_scene_uid=scene_id differing_count")
for path, tres, matching_scenes, differing_scenes in matches:
    print(f"{path}; uid={tres[0]} id={tres[1]} file={tres[2]} "
          f"same={len(matching_scenes)} diff={len(differing_scenes)}")
    for uid, eid, tscn in differing_scenes:
        print(f"  DIFF: {tscn}: uid={uid} id={eid}")
PY

Repository: Project-N-E-K-O/K.U.R.O

Length of output: 2463


同步这些 Texture2D 的外部 UID 喵。

这些 .tres 已使用新的 UID,但同路径对应场景仍保留旧 UID,会破坏 Godot 的资源身份一致性喵。除现有场景外,还需要确认这些资源是否在其他 .tscn/.tres 引用中被同步喵。

📍 Affects 9 files
  • resources/items/Furniture_C_FoodCartA.tres#L8-L8 (this comment)
  • resources/items/Furniture_C_TableRoundC.tres#L8-L8
  • resources/items/Furniture_D_PrinterMachineA.tres#L8-L8
  • resources/items/Furniture_D_TableOfficeB_rwd.tres#L8-L8
  • resources/items/Furniture_D_WaterMachineA.tres#L8-L8
  • resources/items/Furniture_D_WhiteBoardA.tres#L8-L8
  • resources/items/Weapon_Brawl_MechGlove.tres#L5-L5
  • resources/items/Weapon_Brawl_RiotGlove.tres#L5-L5
  • resources/items/Weapon_Slash_BunnySword.tres#L5-L5
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@resources/items/Furniture_C_FoodCartA.tres` at line 8, 同步这些 Texture2D 外部资源的
UID,确保与同路径场景及资源中的 UID 一致;检查并更新
resources/items/Furniture_C_FoodCartA.tres:8、Furniture_C_TableRoundC.tres:8、Furniture_D_PrinterMachineA.tres:8、Furniture_D_TableOfficeB_rwd.tres:8、Furniture_D_WaterMachineA.tres:8、Furniture_D_WhiteBoardA.tres:8、Weapon_Brawl_MechGlove.tres:5、Weapon_Brawl_RiotGlove.tres:5、Weapon_Slash_BunnySword.tres:5,并搜索其他
.tscn/.tres 引用同步相同资源的 UID。

[ext_resource type="Script" uid="uid://dklt5k3rq7qjb" path="res://scripts/actors/enemies/EnemyB2Fat02.cs" id="1_gvrrx"]
[ext_resource type="Resource" uid="uid://d2yxetxicyb1b" path="res://resources/loot/Enemy_B_NormalDrops.tres" id="2_ooggc"]
[ext_resource type="Script" uid="uid://bmrdoiyhd61t4" path="res://scripts/actors/enemies/EnemyB2Fat02.cs" id="1_gvrrx"]
[ext_resource type="Resource" uid="uid://cxoksd62s5rbw" path="res://resources/loot/Enemy_NormalDrops.tres" id="2_s42mu"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

for file in \
  resources/loot/Enemy_NormalDrops.tres \
  resources/loot/Enemy_B_NormalDrops.tres \
  resources/loot/Enemy_C_NormalDrops.tres \
  resources/loot/Enemy_EliteDrops.tres \
  resources/loot/Enemy_C_EliteDrops.tres
do
  if [[ -f "$file" ]]; then
    echo "===== $file ====="
    nl -ba "$file" | sed -n '1,260p'
  fi
done

echo "===== 场景掉落表绑定 ====="
rg -n -C 2 'LootTable\s*=' \
  scenes/actors/characters/Enemy_B2_fat02.tscn \
  scenes/actors/characters/Enemy_C1_waiterA.tscn \
  scenes/actors/characters/Enemy_C1_waiterB.tscn \
  scenes/actors/characters/Enemy_C2_waiterA02.tscn \
  scenes/actors/characters/Enemy_D1_corpDoneA.tscn \
  scenes/actors/characters/Enemy_D1_corpDoneB.tscn

Repository: Project-N-E-K-O/K.U.R.O

Length of output: 252


🏁 Script executed:

#!/bin/bash
set -euo pipefail

for file in \
  resources/loot/Enemy_NormalDrops.tres \
  resources/loot/Enemy_B_NormalDrops.tres \
  resources/loot/Enemy_C_NormalDrops.tres \
  resources/loot/Enemy_EliteDrops.tres \
  resources/loot/Enemy_C_EliteDrops.tres
do
  if [[ -f "$file" ]]; then
    echo "===== $file ====="
    awk '{printf "%7d\t%s\n", NR, $0}' "$file" | sed -n '1,260p'
  else
    echo "missing: $file"
  fi
done

echo "===== 场景掉落表绑定 ====="
grep -RIn -C 2 'LootTable\s*=' \
  scenes/actors/characters/Enemy_B2_fat02.tscn \
  scenes/actors/characters/Enemy_C1_waiterA.tscn \
  scenes/actors/characters/Enemy_C1_waiterB.tscn \
  scenes/actors/characters/Enemy_C2_waiterA02.tscn \
  scenes/actors/characters/Enemy_D1_corpDoneA.tscn \
  scenes/actors/characters/Enemy_D1_corpDoneB.tscn || true

echo "===== 所有 L 区域掉落表文件 ====="
find resources/loot -maxdepth 1 -type f -name 'Enemy_*Drops.tres' | sort | while read -r file; do
  echo "--- $file ---"
  grep -n 'Entries\|Resource\|path=' "$file" | sed -n '1,220p'
done

Repository: Project-N-E-K-O/K.U.R.O

Length of output: 33130


确认掉落合并对游戏平衡的影响喵。

Enemy_NormalDrops GlobalDropChance0.25,与 C 区普通掉落相同;但通用表加入了更多物品,掉落池更宽喵。
Enemy_C_EliteDrops 原本只有两项,现在 Enemy_C1_waiterB.tscn 绑到项数更多的通用精英掉落表,可能改变精英掉落概率喵。
C/D 区新增通用普通掉落绑定是否属于设计预期,请在游戏平衡角度确认喵。

📍 Affects 6 files
  • scenes/actors/characters/Enemy_B2_fat02.tscn#L4-L4 (this comment)
  • scenes/actors/characters/Enemy_B2_fat02.tscn#L81-L81
  • scenes/actors/characters/Enemy_C1_waiterA.tscn#L5-L5
  • scenes/actors/characters/Enemy_C1_waiterA.tscn#L78-L78
  • scenes/actors/characters/Enemy_C1_waiterB.tscn#L11-L11
  • scenes/actors/characters/Enemy_C1_waiterB.tscn#L106-L106
  • scenes/actors/characters/Enemy_C2_waiterA02.tscn#L5-L5
  • scenes/actors/characters/Enemy_C2_waiterA02.tscn#L71-L71
  • scenes/actors/characters/Enemy_D1_corpDoneA.tscn#L4-L4
  • scenes/actors/characters/Enemy_D1_corpDoneA.tscn#L79-L79
  • scenes/actors/characters/Enemy_D1_corpDoneB.tscn#L6-L6
  • scenes/actors/characters/Enemy_D1_corpDoneB.tscn#L90-L90
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scenes/actors/characters/Enemy_B2_fat02.tscn` at line 4, 确认 Enemy_NormalDrops
与 Enemy_C_EliteDrops 的物品数量及 GlobalDropChance 是否符合游戏平衡,并核实 C/D
区新增通用普通掉落绑定是否为设计预期;若非预期,恢复对应敌人的原掉落表或调整掉落配置。涉及
scenes/actors/characters/Enemy_B2_fat02.tscn(4-4、81-81)、Enemy_C1_waiterA.tscn(5-5、78-78)、Enemy_C1_waiterB.tscn(11-11、106-106)、Enemy_C2_waiterA02.tscn(5-5、71-71)、Enemy_D1_corpDoneA.tscn(4-4、79-79)和
Enemy_D1_corpDoneB.tscn(6-6、90-90);逐一确认这些资源绑定与精英掉落概率,非预期位置需要直接修正,预期位置无需改动。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants