Commit Graph
43 Commits
Author SHA1 Message Date
joywayer 06f0049221 fix(shop): can_buy_attribute 同样校验属性已接线;订正路线图残留表述
购买路径是独立守门人:货架 B / 出售退款等后来者会直接调 can_buy_attribute
而不必先过 get_sellable_attrs,只在展示侧拦截不足以保住不变量。未接线属性
生效值恒为 0,_at_soft_cap 因此永不封顶,可被无限买成空气。

同时把路线图第 99 行残留的「加属性零代码」括注收敛到下一条 ⚠️ 订正,避免
同一条目里两句话互相矛盾。
2026-08-03 13:02:20 +08:00
joywayer 5889b3c1e5 fix(shop): 可售属性排除未接线项,修正路线图「零代码」表述
get_sellable_attrs() 此前只看 attributes.json 是否有 shop 段,不看 PlayerStats
是否真的实现了该属性。运行时实测:给一个合成属性加 shop 段(不改任何代码)会被列出、
可买、扣钱、购买计数增加,但 get_attr_value 永远读到 0.00——玩家买到的是空气,
且 _at_soft_cap 因为 0.0 < soft 永远不封顶,变相无限花钱买无效果。

PlayerStats 新增 has_attr(attr_id) 谓词(查 _attr_effective,只有 _recompute_attrs
真正算过的属性才算数,不是查 _attr_def 有没有这一节);get_sellable_attrs 用它做
第二道过滤。诊断特意拆进独立函数 _report_unwired_shop_attrs 才调用 push_error+assert——
实测 assert(false) 在本项目运行环境下会让「当前函数」提前返回声明类型的默认值:若诊断写
在收集循环里,一旦命中就会让 get_sellable_attrs 本身连同已收集好的合法属性一起返回空数组,
比原来的「静默卖空气」更糟(整个货架消失);拆成独立函数调用后,中断只发生在诊断函数
自己的调用帧内,调用方(get_sellable_attrs)仍会正常继续并返回过滤后的正确列表。
已注入未接线属性验证:4 个合法属性照常出现,注入项被排除,无一致性问题。

顺带订正路线图 docs_dev/plans/2026-07-23-missing-features-roadmap.md 里「加 shop 段
即可上架、零代码」的表述——该结论只在属性已先接入 PlayerStats 框架(player_stats.gd
的裸字段 + _recompute_attrs 分支 + _attr_effective 条目,以及 attribute_tab.gd 的
ATTR_ORDER)之后才成立,E3-① 延后的 7 个属性都还没有这一步;同时记录商店属性子面板
当前坐标最多容纳 6 行的限制,供后续实现者提前规划。
2026-08-03 12:51:13 +08:00
joywayerandClaude Opus 5 ad98f916e9 feat(shop): 商店「属性」区独立子面板 UI + 4 语言 i18n 键
主商店面板已无空间容纳四行属性(面板 y=200~540,既有控件已占到 y≈522,仅剩约 18px),
经确认后改为独立子面板方案(参照 _setup_settings_ui 既有模式),不改动主面板任何既有控件坐标。

按 get_sellable_attrs() 动态生成行,加可售属性无需改 UI 代码。
禁用态显示具体原因(金币不足/已达上限)而非只灰掉按钮。
can_buy_attribute 注释补 i18n 债务说明(禁用原因暂未 tr(),见路线图 E7-③)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 11:46:05 +08:00
joywayerandClaude Opus 5 900eaea697 feat(shop): 货架 C 购买次数进局内存档(schema 2→3)
只存次数不存加成——加成是派生物,回读时经 _apply_attr_purchases 重建。
这也躲开了 E3-① 记录的坑:_modifiers 是 Array[Dictionary],而 JSON 回读的
无类型 Array 直接 = 赋值是运行时类型错误,必须 .assign();存派生源头则不涉及。

回读顺序:attr_purchases 必须早于 load_save_data。后者设 hp,而重建加成会经
_recompute_attrs 触发 hp = minf(hp, hp_max);顺序颠倒会拿未加成的 hp_max 去钳,
静默吞血(hp_max 可买到 180 后即可复现)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 11:27:23 +08:00
joywayerandClaude Opus 5 f8e02b0a0b fix(shop): pct 合并公式按 combine 分支取值,修正 inverse 属性算错
_apply_attr_purchases() 原公式 merged=(1+step)^n−1 只对 AttributeFormula 的
hybrid 分支(f=1+v)成立;inverse 分支用 f=1−v,四个可售属性里 cast_delay_mod
恰是 inverse+pct,实际把 f 算成 2−1.1^n 而非设计意图的 0.9^n——n=7 时应得
0.478,实得 ≈0.0513,可购买次数从设计的约 22 次被砍到约 7 次即撞 soft,且
全程 f≥0 走不到越界钳制分支,零诊断。

这是 Task 2 简报 spec 本身推导错误(简报只在 hybrid 下验证过等价性),非
实现偏差;评审已订正 spec 与计划(68e3edb)。现按订正后的公式补上按
combine 分支取值:hybrid 用 merged=(1+step)^n−1,inverse 用
merged=1−(1−step)^n,flat 与 combine 无关不变。

补测显式覆盖此前遗漏的 inverse+pct 组合(此前运行时验证只买过
move_speed/hp_max/cpu_limit,唯独没买过 cast_delay_mod——测试盲区精确盖住
了 bug 所在处):n=1..3/7 逐点数值比对(容差 1e-6),并确认 soft 封顶购买
次数从 ~7 恢复到 ~22;hybrid/flat 对照组数值不变。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 11:19:23 +08:00
joywayerandClaude Opus 5 622da4a18e feat(shop): 货架 C 状态与购买——shop 段驱动可售集合,唯一写入点重建加成
可售集合纯数据驱动:attributes.json 的 shop 段缺失即不可售,将来解除 7 个
被阻塞属性的前置后只需加一段 JSON,零代码。

PlayerStats 新增通用生效值访问器 get_attr_value(attr_id),消除商店/UI 侧
本应出现的三处硬编码 match attr_id;_attr_effective 与裸字段在同一处
(_recompute_attrs)更新,避免两者不同步导致显示值与生效值脱节。

_attr_purchases 只存次数;每属性至多一条 _modifiers、value 为合并值
(pct 下 n 次 +step 等价于单条 (1+step)^n − 1)。这样出售退款只需次数减一后
重算,不必给 PlayerStats 新增按条撤销的 API。

所有改动次数的路径都收在 _apply_attr_purchases()——两份状态不同步会产生
「显示买了 3 次但加成只有 2 次」且无任何诊断,收敛写入点是唯一防线。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 11:11:08 +08:00
joywayerandClaude Opus 5 9361bf8767 refactor(attr): "core" 来源提为常量;_compute_attr 补 assert;注明 execute_sub 预算独立
MOD_SOURCE_CORE 常量取代四处裸字面量(combat_manager:275,276、combat_test:20,21)。
combat_manager:273 的注释自己就警告「漏掉 remove 会累积,且 hard:50 会把它封成一个
看起来合理的数字」——而 remove 那一侧的字面量若打错一个字符,产生的正是这个零诊断
故障:旧份额撤不掉、逐次累积、被硬上限封顶成常数。常量把它变成编译期错误。

_compute_attr 缺定义时返回 0.0 是消费侧的不对称:Task 4 已硬化生产侧(attribute_tab
的 _loaded 拒绝写出零载荷),但手删 JSON 里的 cast_delay_mod 仍会让生效间隔变 0
(每物理帧施法一次)、删 move_speed 则玩家不能动。它有 push_error,但运行时 push_error
到不了任何日志通道(本期已实测),故表现为一块莫名其妙的砖。按 _recompute_attrs 空定义
分支的同款模式补 assert:release 编译掉、开发期立刻中断。

spell_evaluator:332 的新注释说「生效 cpu_limit 已含法杖份额」,读者可能推断整个 VM 都按
cpu_limit 走,但 execute_sub 的子荷载预算仍是独立的 MAX_OPS_PER_CPU * 2(=80)。补一句
注明其独立且属既有行为(改前同样脱节),不改 execute_sub 的行为。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 13:37:15 +08:00
joywayerandClaude Opus 5 69ddcddba6 docs(attr): 补记货架 C 的回读顺序陷阱;畸形条目报错说明整文件已拒绝
纯注释改动,无行为变更。

1. get_save_data 的货架 C 文档块补回读顺序:_modifiers 必须先 assign +
   _recompute_attrs(),再赋 hp。反过来会让新加的 hp = minf(hp, hp_max) 拿
   未加成的 hp_max 去钳,静默吞血(评审复现:回读 hp=180/100 → 换杖重算后
   100/100,丢 80 HP)。今天不可达(hp_max 恒 100),但持久化 _modifiers 一
   落地即活,而这个文档块正是那位实现者会读的地方。

2. 畸形条目的 push_error 补「整个文件已拒绝加载」——守卫是 return,一个坏
   条目会让四个属性全部退回声明默认值,原文案读起来像只影响那一个键。

3. ATTRIBUTES_JSON 补「数据源」分区横幅,与文件自身风格一致。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 11:32:10 +08:00
joywayerandClaude Opus 5 af9c94db25 fix(attr): add_modifier 补校验、hp 随 hp_max 调和、reset_for_run 清加成
评审 Changes needed 的三个 Important + 五条 Minor:

1. add_modifier 补 attr_id / mode 校验。AttributeFormula 的注释明文把校验委托
   给本函数("仅由 PlayerStats.add_modifier 构造…此处不做防御性校验"),而它
   原先不守任何门:打错的 attr_id 会永远堆在 _modifiers 里、永不被读到、零诊断。
   Task 3 的 add_modifier("cpu_limit",…) 若打成 "cpu_limits" 即 MAX_OPS=0,
   所有法术静默执行零步。

2. _recompute_attrs 补 hp = minf(hp, hp_max)。hp_max 改动前事实上不可变,现在
   是可动派生值而 hp 从不调和:买 +100 hp_max、血 180/200、卖掉 → 显示 180/100、
   get_hp_percent 返回 1.8、heal 静默失效。

3. reset_for_run 清 _modifiers 并重算,且必须早于 hp = hp_max,否则 hp 用陈旧
   的 hp_max 播种。今天 "core" 靠 _rebuild_wand 自愈,但货架 C 的购买会跨局白嫖。

Minor:_ATTR_PATH → ATTRIBUTES_JSON 并上移(_PATH 后缀在本项目专指 user:// 路径,
同类 autoload 一律 XXX_JSON);_mods_for 返回 Array[Dictionary];加载器逐条守卫
畸形值("move_speed": 200 会让 Dictionary 赋值硬崩);remove_modifiers_from 无
命中时提前返回不空发 stats_changed;货架 C 提示并入 get_save_data 并补记回读须
用 .assign()(无类型 Array 赋给 Array[Dictionary] 是运行时错误)。

_recompute_attrs 的空定义分支用 assert 而非 push_error:Task 3 接线后每次换杖/
换牌/购买都触发重算,无条件报错一局刷上百行、反而埋掉根因;assert 在 release
被编译掉且开发期首次调用即中断。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 11:24:30 +08:00
joywayerandClaude Opus 5 a4a4f613f4 feat(attr): attributes.json + PlayerStats 属性框架;删孤儿字段 armor/resistance
PlayerStats 只负责加载定义、持有加成列表、把公式结果写进静态类型裸字段,
不含任何公式(公式在 AttributeFormula)。读取端零开销以满足热路径纪律
(move_speed 每物理帧被 player_manager 读)。

armor/resistance 零消费方且不在 numerical_design §1.1 权威属性表内,属实现
先于设计的残留,删除;真要做玩家侧减伤时按货架 C 属性词条立项(见 spec §2.6)。

hp_max/cpu_limit 现为派生值,从存档字段移除——回读会覆盖公式结果。
旧存档相应键忽略即可,无需提升 schema 版本(hp_max 全项目从无写入方、
cpu_limit 从未被读取)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 11:07:59 +08:00
joywayerandClaude Opus 5 4b09cd1064 fix(homing): 抖动公式的整数除法加 @warning_ignore,消掉 INTEGER_DIVISION 告警
(bullet_idx * HOMING_RETRY_MS) / maxi(1, _active_count) 的截断是有意的 ——
抖动只需毫秒粒度的偏移,小数部分丢弃即所需语义。加注解让编辑器面板对
项目文件保持零告警,使验收标准⑩「无告警」真正成立。

行为不变(注解为编译期),复测:①②③ FAILS=0 / ah=0.25000 / max_step=0.050000
/ 速率 350.0000;1500 弹同帧集体失败的到期时刻跨度 223ms、222 个互异值,抖动照常生效。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 17:32:43 +08:00
joywayerandClaude Opus 5 28f4047096 fix(homing): bounce 协同路径遗留过期退避键,使子弹对着尸体转向且拒绝重新锁定
homing_target_id 有两个写入方,不变式「homing_retry_at 只在目标无效时才有意义」
只在其中一方成立:_apply_homing 重选成功时会 erase 该键,bounce 那行不会。
后果是一颗 bounce+homing 子弹若先经历过一次重选失败、再弹跳到 next_id、而 next_id
随即死亡(弹跳目标是刚打过的敌人,随即死亡是常态),它会对着尸体继续转向,并在
残留退避窗口内(最多 400ms ≈ 24 帧)拒绝重新锁定,哪怕 50px 外就有活敌人。
这恰好废掉了那行 bounce 协同代码存在的意义。

修法与重选成功路径对称,补一行 cold.erase("homing_retry_at")。运行时复现确认:
  阶段1 重选失败 -> retry_at 存在=true, tgt=-1
  F bounce 后: tgt=3 (expect 3) retry_key_still_present=false   (修前 true)
  F 目标死亡后能否立刻重选: tgt=4 重选成功=true                  (修前被残留退避压住停在 3)

另两处:
- 调用方守卫注释的「省约 87%」改为 64% —— 87% 出自代理微基准推算,已被真实
  端到端实测(2.107→1.812ms)推翻,热路径里挂陈旧乐观数字会误导后来人判断该守卫去留。
- jitter 取模的 6 行不可达性论证压缩为一行(运算保留作索引越界兜底,成本为零)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 16:26:17 +08:00
joywayerandClaude Opus 5 71240931af perf(homing): 退避到期时刻加抖动,消除每 12 帧复发的集体重试尖峰
二次发现:固定 200ms 退避并没有消除尖峰,只是让它变成周期性复发。按真实 60fps
起搏复测,1500 弹 visited 场景逐帧耗时在第 1/13/25/37 帧稳定出现 ~21ms,永不衰减:
  21.9 2.8 2.9 ... 3.1 | 21.8 2.8 ... | 21.0 2.9 ... | 20.9 3.7 3.9 3.8
根因是朴素退避会把子弹锁进同相而非打散 —— 同帧失败的子弹拿到同一个 now,到期时刻
完全相同,一个退避周期后又整齐地一起重试;同波齐射本就天然同相,此后再无机会错开。
摊薄后的均值数字恰恰掩盖了这一点。

修法是抖动到期时刻,铺满 [200,400) ms ≈ 恰好一个退避周期 ≈ 12 帧。
用「bullet_idx 在活跃弹数中的占比」而非 bullet_idx % HOMING_RETRY_MS:后者在弹数少于
窗口宽度时只铺开 _active_count 毫秒(20 颗弹 → 20ms ≈ 1.2 帧,等于没打散)。
实测打散质量:1500 颗同帧集体失败 → 互异到期值 1493 个、覆盖 14 帧、单帧最多 120 颗
(理想 125)。

单帧峰值(60fps 起搏 40 帧,稳态即排除初次锁定帧):
  ① 全射程外 1500  13.6~15.7ms 复发 → 4.40ms   300  3.2ms → 0.92ms
  ② 全 visited 1500  20.9~21.9ms 复发 → 5.61ms  300  4.6ms → 1.15ms
稳态超 16.67ms 的帧数均为 0/39。

首次锁定即时的行为未受影响(抖动只作用于失败后的重试),速率守恒、单帧转角上限、
退避窗口内零查询、到期后重试成功并 erase 键,断言全绿。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 16:12:40 +08:00
joywayerandClaude Opus 5 c9786eba50 fix(bullet): _swap_and_pop 回收末尾子弹时遗留冷数据,被下一颗复用槽位的子弹继承
pre-existing bug(非本期归航引入):冷数据的搬移与擦除都写在 if idx != last 分支内,
故 idx == last(回收最后一颗子弹)时它的 _bullet_contexts[idx] 被原样留在该 key 上,
下一颗复用该槽位的普通子弹会继承整份冷数据。运行时已复现:
  after recycle: active=0 ctx_keys=[0]
  plain bullet idx=0 inherits_cold=true cold={"homing_strength":3.0,...,"pierce_remaining":7}

归航之前症状只是一次隐形的多余穿透,故长期未被发现;归航把它放大成肉眼可见的
「普通子弹拐弯追敌」,且继承 homing 的幽灵弹会持续走重选路径付出查询开销。
修法是把 erase 移出该 if(缺键时 erase 为安全 no-op),idx != last 的搬移行为一行不改。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 16:02:39 +08:00
joywayerandClaude Opus 5 2f9cb76308 perf(homing): 重选失败退避 0.2s + homing 判别提到调用方
评审实测发现两种病态状态下重选会每帧无限重试,query_circle(r=400) 进入热路径:
① 敌人在场但全在 homing_range 外;② 射程内敌人全在 visited_targets 里
(bounce+homing 打空小簇后是该子弹的永久状态,原 spec 风险分析漏掉了这种)。
1500 弹实测 15.8ms / 22.0ms,300 弹 3.1ms / 4.3ms,均越过 spec §5 的 2.0ms 触发线,
故 spec §5 记录的逃生方案(方案 3)提前落地:重选失败写 homing_retry_at 时间戳,
HOMING_RETRY_MS(200ms) 内直行不再查询,60fps 下摊薄约 12×。
首次锁定不受影响(无该键时 get 返回 0 必小于 now),手感不回退;
重选成功即 erase 该键,恢复零查询稳态。

homing 判别 _bullet_contexts[i].has("homing_strength") 提到 _gd_integrate 调用方:
带冷数据但不归航的子弹(纯 pierce/bounce/状态/荷载,真实 build 里占多数)不再
为发现自己不归航而付一次完整函数调用 —— 1500 纯 pierce 弹实测 2.107→1.812ms。
_apply_homing 内的 strength <= 0.0 早退保留作防御性下限。

同步订正两处失准注释:_find_nearest_unvisited 现也是归航选目标器;
_apply_homing 文档注释补齐失败路径的重试/退避策略。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 16:01:31 +08:00
joywayerandClaude Opus 5 b3b04fcbda feat(homing): bullet_manager 受限角速度转向 + 锁定式目标重选 + bounce 协同; 删除无人消费的位置快照
_apply_homing 在位置积分前把速度矢量朝目标旋转,单帧转角上限 strength*delta,
rotated() 保持速率不变;wrapf 取最短转向方向。
目标仅在失效或首帧时经 _find_nearest_unvisited 重选,配 get_active_count()==0
空场守卫,避免 query_circle(r=400) 进入每帧热路径。
bounce 命中重定向时改写 homing_target_id,由 bounce 选目标 homing 追上去。
删除 _enemy_pos_snapshot 及 EnemyManager.fill_pos_snapshot(全项目唯一调用方)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 15:40:55 +08:00
joywayerandClaude Opus 4.8 3eb6049b39 feat(bounce): bullet_manager 命中弹跳分支(优先于pierce)+跳过已访问+_find_nearest_unvisited 寻的
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 15:11:16 +08:00
joywayerandClaude Opus 4.8 fe1d1f690f feat(resist): EnemyManager 元素抗性加载+命中查表;enemies.json Fast 种子抗火弱冰
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 11:51:53 +08:00
joywayerandClaude Opus 4.8 23644bb40b feat(iframe): PlayerStats.take_damage 时间戳门控无敌窗口 + 复活 PLAYER_DAMAGED emit;移除死订阅
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 09:18:54 +08:00
joywayerandClaude Opus 4.8 daf34ac1bb feat(iframe): balance.json 增 player_iframe_sec 键 + SettingsManager 访问器(默认0.5s)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 09:15:48 +08:00
joywayerandClaude Opus 4.8 2a7658e0e3 fix(hot-path): 回退 query_circle 复用缓冲优化——存在重入覆写 bug
上个提交 35c1742 让 query_circle 复用成员 _query_result 缓冲,实测有重入缺陷:
GDScript 的 PackedArray 返回值是活引用别名(非写时复制副本),当调用方遍历返回
的 hits 期间触发嵌套 query_circle(命中→SpellEvaluator.execute_sub 的区域法术),
嵌套调用的 clear()+append 会就地覆写外层正在遍历的同一缓冲,导致碰撞遍历读到错误
实体 ID。编辑器内已复现:外层期望 [10,20,30],重入后实得 [10,88]。

原优化仅省约 0.064ms/帧(帧预算 ~0.4%),不值得为其做跨 4 处调用点的 out 参数
+ 各自持久缓冲的重入安全改造,故回退为每次新建数组。
BulletManager 无冷数据命中快路径无重入问题,保留。
并加注释说明此处禁止复用缓冲的原因。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 16:35:31 +08:00
joywayerandClaude Opus 4.8 35c1742b4c perf(hot-path): SpatialGrid.query_circle 复用结果缓冲 + BulletManager 无冷数据命中快路径
纯 GDScript 层零成本优化(不引入 C#/C++,遵循「先测量后优化」):
- spatial_grid.gd: query_circle 改用持久成员 _query_result(clear()+append 就地填充后返回),
  避免每次调用(每帧 1500+ 次)新建 PackedInt32Array。经引擎实测 ~11% 提速、逐点校验
  2000 次查询结果与原实现完全一致;CoW 语义保证嵌套查询(命中→SpellEvaluator 区域查询)
  不破坏调用方正在遍历的旧结果。
- bullet_manager.gd: _check_collision 命中处理为无冷数据的普通子弹加快路径,
  避免 _bullet_contexts.get(bullet_idx, {}) 每次命中都分配空字典默认值 + 5 次字典查。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 16:13:33 +08:00
joywayer 95e5587049 fix(boss): HUD 阶段提示改 tr(STATUS_BOSS_PHASE)+4语言 .po;register_boss 未知 boss_type push_error 2026-07-23 11:07:52 +08:00
joywayer f8efdc639d fix(boss): 防玩家死亡致命一击重入 —— EnemyBulletManager._swap_and_pop 负数守卫 + BossManager 循环内失效键跳过 2026-07-23 10:54:29 +08:00
joywayer aa516bcb50 feat(boss): wave_manager 接入 BossManager(移除旧内联阶段逻辑)+ combat_manager 重置敌弹/Boss 2026-07-23 10:22:25 +08:00
joywayer af535f1ed0 feat(boss): 位移/蓄力/近战招式 dash/charge_up/melee(三段式+前摇预警+接管移动) 2026-07-23 10:17:18 +08:00
joywayer c566eb16a0 feat(boss): 瞬时远程弹幕招式 ring/spread/aimed/spiral(经 EnemyBulletManager 发射) 2026-07-23 10:12:21 +08:00
joywayer f8b05551e2 feat(boss): BossManager 阶段状态机+漂移移动+进阶召唤+BOSS_PHASE_CHANGED/KILLED(招式骨架) 2026-07-23 10:06:28 +08:00
joywayer 531706ba62 feat(boss): EnemyManager 外部驱动移动接口(register/unregister_external_mover + set_entity_pos + 跳过) 2026-07-23 10:00:14 +08:00
joywayer f5d94a52f0 feat(boss): 新增 EnemyBulletManager 敌方子弹子系统(SoA 池 + vs 玩家碰撞) 2026-07-23 09:49:32 +08:00
joywayer 29d387aebc feat(boss): 事件常量 BOSS_PHASE_CHANGED=29 / BOSS_KILLED=30 + 目录同步 2026-07-23 09:43:44 +08:00
joywayer b55e6eaadf feat(mana): 魔力虹吸多来源(Core base + 卡组 meta.mana_leech 求和,换杖重算) 2026-07-21 15:16:37 +08:00
joywayer a57348a9f7 feat(mana): PlayerStats mana_heat/leech+gain_mana/spend_hp_cost+击杀回蓝;SpellContext hp_cost_accum 2026-07-21 15:10:54 +08:00
joywayer 7025f283f8 feat(mana): balance.json mana_heat/infinite_spells 配置 + SettingsManager getters 2026-07-21 15:09:28 +08:00
joywayer 3ebbcc2f34 修改配置 2026-07-21 12:06:10 +08:00
joywayerandClaude Opus 4.8 958d53636c refactor(meta): aether_for_wave 取 maxi 容忍无序阈值表(复审建议,编辑器手填更稳)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 11:58:11 +08:00
joywayer 7682480a5f feat(meta): 商店池按 unlock_cost/已解锁门控(_available_pool) 2026-07-21 11:45:32 +08:00
joywayer d6f4f2b5a6 feat(meta): 碎片奖励阈值表(balance.json)+aether_for_wave+清除数据钩子 2026-07-21 11:43:28 +08:00
joywayer e8d0c06440 feat(meta): MetaProgress autoload(碎片+已解锁+持久化 user://meta.json) 2026-07-21 11:42:18 +08:00
joywayer 17aaad3589 feat(mana): PlayerStats 蓝池状态 + spend/regen/set_pool + reset 置满 2026-07-20 16:26:12 +08:00
joywayer 94a78d1a4c feat(mana): CoreDefinition 加 base_mana_max/regen + cores.json 数据 2026-07-20 16:24:36 +08:00
joywayerandClaude Opus 4.8 dc05eeada7 fix: 修复审计发现的 3 个潜在 bug(CoreFeatureTag / pierce / Deck 防呆)
1. CoreFeatureTag 位运算串扰:feature_tags 实为单选枚举(游戏设计器 core_tab
   以 OptionButton 下标写入),但 spell_evaluator 用位与 `&` 判定,非 2 的幂
   常量会串扰(如 3 & 1 = 1 误判持久内存)。改为 `==` 相等判定,常量值保持
   与设计器下标一致;补充注释说明单选语义与未来多选(位标志)的迁移路径。
2. modifier_pierce_plus 空操作:MODIFIER 携带的 pierce 从未生效(可购买无效)。
   新增 CastStats.pierce_add,_apply_modifier 累加,_push_projectile 叠加到
   ACTION 自带 pierce。穿透修正现在生效。
3. 战前 Deck 防呆缺失:可带无 ACTION 卡组进战斗。新增
   CombatManager.has_castable_action();商店"下一波"按钮校验,无 ACTION 时
   显示警告并阻止进入(新增 SHOP_NEED_ACTION i18n 键,zh_CN/zh_TW/en/ja)。

静态审查通过;因本机无 Godot CLI 未经运行时验证,需在编辑器 play_scene 验收。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 14:46:41 +08:00
joywayer 7bcc0026e0 初次提交 2026-07-20 10:56:52 +08:00