feat(homing): CastStats.homing_add + 修饰器折叠 + 发射写归航冷数据 + 分支快照; modifier_homing 词条

homing_add 为 float(角速度,弧度/秒),镜像 bounce_add 的 int 累加路径。
发射时不解析目标,homing_target_id 留 -1 由 bullet_manager 首帧惰性获取,
使 spell_evaluator 不必接触 SpatialGrid。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-30 15:24:17 +08:00
co-authored by Claude Opus 5
parent 364ebe4c62
commit 5663dedc12
3 changed files with 13 additions and 1 deletions
@@ -13,6 +13,7 @@ var radius_mult: float = 1.0 # 弹体半径倍率
var crit_chance: float = 0.0 # 暴击概率
var pierce_add: int = 0 # MODIFIER 累加的穿透次数(叠加到 ACTION 自带 pierce
var bounce_add: int = 0 # MODIFIER 累加的弹跳次数(叠加到 ACTION 自带 bounce
var homing_add: float = 0.0 # MODIFIER 累加的归航角速度(弧度/秒,叠加到 ACTION 自带 homing)
func reset() -> void:
damage_add = 0.0
@@ -25,3 +26,4 @@ func reset() -> void:
crit_chance = 0.0
pierce_add = 0
bounce_add = 0
homing_add = 0.0
+10 -1
View File
@@ -436,6 +436,11 @@ func _push_projectile(node: SpellNode, ctx: SpellContext, spawn_pos: Vector2, tr
cold["visited_targets"] = []
cold["bounce_decay"] = float(meta.get("bounce_decay", 0.9))
cold["bounce_range"] = float(meta.get("bounce_range", 250.0))
var homing: float = float(meta.get("homing", 0.0)) + ctx.stats.homing_add
if homing > 0.0:
cold["homing_strength"] = homing
cold["homing_range"] = float(meta.get("homing_range", 400.0))
cold["homing_target_id"] = -1
# S3: 将 trigger_depth 写入冷数据供子弹命中时使用
if trigger_depth >= 0:
cold["trigger_depth"] = trigger_depth
@@ -531,6 +536,8 @@ func _apply_modifier(node: SpellNode, ctx: SpellContext) -> void:
ctx.stats.pierce_add += int(meta["pierce"])
if meta.has("bounce"):
ctx.stats.bounce_add += int(meta["bounce"])
if meta.has("homing"):
ctx.stats.homing_add += float(meta["homing"])
if meta.has("heavy_cost"):
ctx.hp_cost_accum += float(meta["heavy_cost"])
@@ -612,7 +619,7 @@ func _run_branch_payload(payload_id: int, ctx: SpellContext, spawn_pos: Vector2,
var nodes: Array = SubPayloadRegistry.get_nodes(payload_id)
if nodes.is_empty():
return
# 快照分支前 CastStats9 字段,无分配),分支结束后还原 → 分支局部 MODIFIER 不外泄
# 快照分支前 CastStats10 字段,无分配),分支结束后还原 → 分支局部 MODIFIER 不外泄
var s: CastStats = ctx.stats
var b_dadd: float = s.damage_add
var b_dmul: float = s.damage_mult
@@ -623,6 +630,7 @@ func _run_branch_payload(payload_id: int, ctx: SpellContext, spawn_pos: Vector2,
var b_rad: float = s.radius_mult
var b_crit: float = s.crit_chance
var b_bnc: int = s.bounce_add
var b_hom: float = s.homing_add
for node in nodes:
var node_cost: float = float(node.meta.get("mana_cost", 0.0))
if not _charge_mana(node_cost, ctx, infinite, heat_mult):
@@ -650,6 +658,7 @@ func _run_branch_payload(payload_id: int, ctx: SpellContext, spawn_pos: Vector2,
s.radius_mult = b_rad
s.crit_chance = b_crit
s.bounce_add = b_bnc
s.homing_add = b_hom
func _get_aim_direction(from_pos: Vector2) -> Vector2:
var target: Vector2 = EnemyManager.get_nearest_pos(from_pos, 9999.0)