iter48-卡1:卡①(状态合并累加制批): 六行stack_policy refresh→accumulate+schema词表换代+容器累加臂(_apply_accumulate只加时长,层数快照不变)+roll_multiplier五段式探针(V1/V2/V3)+table_structure_guard V4+damage_controller标签换代+甲案裁决随动(2026-11-02用户裁): _ineffective_row载荷deferred自描述键(非行为改动)+round_flow _row_phase分类补deferred→战斗段——相位单调断言归绿,EV三锚0.9148/1.0012/1.1948逐位不变
This commit is contained in:
1 parent
26f00af7a8
commit
1e35ab947b
9 files changed
+55
-29
No files matched your search
@@ -688,4 +688,4 @@ func _target_for(rule: String) -> Variant:
|
||||
|
||||
func _ineffective_row(t: Dictionary, reason: String) -> void:
|
||||
emit_row_cb.call({"type": "reward_ineffective", "source_class": String(t.source_class), "origin_cell": t.origin_cell, "highlight": String(t.highlight)}, int(t.round_index),
|
||||
"%s 未生效(%s)" % [String(t.display), reason], 0, {"batch_key": String(t.context.get("batch_key", ""))})
|
||||
"%s 未生效(%s)" % [String(t.display), reason], 0, {"batch_key": String(t.context.get("batch_key", "")), "deferred": true})
|
||||
@@ -41,8 +41,8 @@ func apply_effect(effect_id: String, source: Dictionary, duration_override: int
|
||||
"independent":
|
||||
_instances.append(_new_instance(effect_id, 1, dur, source, snap))
|
||||
return true
|
||||
"refresh":
|
||||
return _apply_refresh(effect_id, dur, snap, source)
|
||||
"accumulate":
|
||||
return _apply_accumulate(effect_id, dur, snap, source)
|
||||
"stack":
|
||||
return _apply_stack(effect_id, dur, snap, source, max_stack)
|
||||
push_warning("[增益状态] 未知 stack_policy")
|
||||
@@ -57,11 +57,11 @@ func _grant_snapshot(row: Dictionary, source: Dictionary) -> Dictionary:
|
||||
return {"m": snap_m, "unit": String(row.unit), "display": String(row.display_name)}
|
||||
|
||||
|
||||
## refresh 臂:命中改 R 未命中追加(R ← D 取实例快照 D——同表值;L 不变;空刷新恒 true)
|
||||
func _apply_refresh(effect_id: String, dur: int, snap: Dictionary, source: Dictionary) -> bool:
|
||||
## 累加臂:命中加时长未命中追加(R += D 取本次授予生效时长——覆盖值 ≥1 按覆盖值;L 不变;快照沿首授;每次授予必有剩余次数变化)
|
||||
func _apply_accumulate(effect_id: String, dur: int, snap: Dictionary, source: Dictionary) -> bool:
|
||||
for inst in _instances:
|
||||
if inst.effect_id == effect_id:
|
||||
inst.remaining = dur
|
||||
inst.remaining = int(inst.remaining) + dur
|
||||
return true
|
||||
_instances.append(_new_instance(effect_id, 1, dur, source, snap))
|
||||
return true
|
||||
|
||||
@@ -8,7 +8,7 @@ extends Resource
|
||||
|
||||
const TARGET_SIDES := ["hero", "enemy"]
|
||||
const UNITS := ["percent", "flat", "ac"] # ac——AC 阈值轴效果(ac_up),非池百分比非定点值
|
||||
const STACK_POLICIES := ["stack", "refresh", "independent"]
|
||||
const STACK_POLICIES := ["stack", "accumulate", "independent"]
|
||||
|
||||
|
||||
func validate() -> Array:
|
||||
|
||||
@@ -11,7 +11,7 @@ rows = [{
|
||||
"magnitude": 50,
|
||||
"unit": "percent",
|
||||
"duration_settlements": 1,
|
||||
"stack_policy": "refresh",
|
||||
"stack_policy": "accumulate",
|
||||
"max_stack": 2
|
||||
}, {
|
||||
"effect_id": "ac_up",
|
||||
@@ -20,7 +20,7 @@ rows = [{
|
||||
"magnitude": 1,
|
||||
"unit": "ac",
|
||||
"duration_settlements": 1,
|
||||
"stack_policy": "refresh",
|
||||
"stack_policy": "accumulate",
|
||||
"max_stack": 2
|
||||
}, {
|
||||
"effect_id": "weaken",
|
||||
@@ -29,7 +29,7 @@ rows = [{
|
||||
"magnitude": -65,
|
||||
"unit": "percent",
|
||||
"duration_settlements": 2,
|
||||
"stack_policy": "refresh",
|
||||
"stack_policy": "accumulate",
|
||||
"max_stack": 16
|
||||
}, {
|
||||
"effect_id": "enrage",
|
||||
@@ -65,7 +65,7 @@ rows = [{
|
||||
"magnitude": 100,
|
||||
"unit": "percent",
|
||||
"duration_settlements": 2,
|
||||
"stack_policy": "refresh",
|
||||
"stack_policy": "accumulate",
|
||||
"max_stack": 1
|
||||
}, {
|
||||
"effect_id": "fortify",
|
||||
@@ -74,7 +74,7 @@ rows = [{
|
||||
"magnitude": -50,
|
||||
"unit": "percent",
|
||||
"duration_settlements": 2,
|
||||
"stack_policy": "refresh",
|
||||
"stack_policy": "accumulate",
|
||||
"max_stack": 1
|
||||
}, {
|
||||
"effect_id": "defensive_stance",
|
||||
@@ -83,7 +83,7 @@ rows = [{
|
||||
"magnitude": -25,
|
||||
"unit": "percent",
|
||||
"duration_settlements": 2,
|
||||
"stack_policy": "refresh",
|
||||
"stack_policy": "accumulate",
|
||||
"max_stack": 1
|
||||
}, {
|
||||
"effect_id": "alert",
|
||||
|
||||
@@ -373,7 +373,7 @@ func _test_pool_clamp(db) -> void:
|
||||
var expected1: int = clampi(int(pool_eff.magnitude), lo, hi)
|
||||
Kit.check("池值 = 单实例 L×m 加算后 clamp", first_ok and h.ctrl.clamped_pool("hero_offense") == expected1)
|
||||
var second_ok: bool = h.effects.apply_effect(String(pool_eff.effect_id), src)
|
||||
Kit.check("refresh 政策重复授予受理且层数恒 1(叠层改续时裁决)——池值不变",
|
||||
Kit.check("累加政策重复授予受理且层数恒 1(同名重复授予加时长)——池值不变",
|
||||
second_ok and h.ctrl.clamped_pool("hero_offense") == expected1)
|
||||
# ac 型效果不入 percent 池
|
||||
var ac_eff2 := {}
|
||||
|
||||
@@ -154,13 +154,18 @@ func _smoke_armor_roll() -> void:
|
||||
int(crit_rows.get("roll", -1)) == int(_db.combat.settlement.damage_roll.crit_roll) and bool(crit_rows.get("crit", false)))
|
||||
Kit.check("nat20 → 普通分量 ×2(%d = 2×%d,暴击倍率只乘该分量,穿刺/魔法不吃)" % [int(crit_rows.get("normal", -1)), int(_db.combat.hero.atk)],
|
||||
int(crit_rows.get("normal", -1)) == 2 * int(_db.combat.hero.atk) and int(crit_rows.get("value", -1)) == 2 * int(_db.combat.hero.atk))
|
||||
# ③ 削弱续时(行为面):授予→衰减一轮→再授予 → 层数保持 1、剩余结算数重置
|
||||
# (削弱为续时语义,无叠层通道)
|
||||
var weaken_probe := _weaken_refresh_probe()
|
||||
Kit.check("削弱重复授予 → 层数保持 1、剩余结算数重置 2(续时语义——结构性消饱和)",
|
||||
int(weaken_probe.get("layers", -1)) == 1 and int(weaken_probe.get("remaining", -1)) == 2)
|
||||
# ③ 削弱累加(行为面):授予→衰减一轮→再授予 → 层数保持 1、剩余结算数累加本次授予时长
|
||||
# (削弱为累加语义,无叠层通道)
|
||||
var weaken_probe := _weaken_accumulate_probe()
|
||||
Kit.check("削弱重复授予 → 层数保持 1、剩余结算数累加至 3(1+2——快照沿首授)〔状态累加 V1〕",
|
||||
int(weaken_probe.get("after_regrant", -1)) == 3 and int(weaken_probe.get("layers", -1)) == 1 \
|
||||
and int(weaken_probe.get("snap_magnitude", -9999)) == -65)
|
||||
Kit.check("削弱单层池读数 = 行值(enemy_output 池单层贡献——×2 叠满触底 ×0 不可达,免伤轮根治)",
|
||||
int(weaken_probe.get("pool", -999)) == int(_db.combat.status_effects.row_by_id("weaken").magnitude))
|
||||
Kit.check("削弱覆盖时长重授 → 按覆盖值累加至 6(3+3)〔状态累加 V3〕",
|
||||
int(weaken_probe.get("after_override", -1)) == 6)
|
||||
Kit.check("削弱同轮再授 → 再累加一段至 8(6+2)〔状态累加 V2〕",
|
||||
int(weaken_probe.get("after_extra", -1)) == 8)
|
||||
# ④ AC11 折扣档分布(行为面):ac_up 逐轮授给(时效 1)→ Boss 行攻击拍逐拍判定
|
||||
# (ac_up 层数恒 1——局内可达 AC 上限 10+1=11,探针随行取值)
|
||||
var tiers := _ac11_tier_samples()
|
||||
@@ -215,10 +220,11 @@ func _first_hero_attack_rows(seed_val: int) -> Dictionary:
|
||||
return {}
|
||||
|
||||
|
||||
# 削弱续时探测:
|
||||
# 授予 → 衰减一轮 → 再授予,读 weaken 实例投影 {layers, remaining, pool}。
|
||||
# 削弱累加探测(五段式):
|
||||
# 授予(2) → 衰减一轮(1) → 重授(1+2=3) → 覆盖值重授(3+3=6) → 同轮再授(6+2=8),
|
||||
# 读 weaken 实例投影 {layers, pool, after_regrant, after_override, after_extra, snap_magnitude}。
|
||||
# 直授通道(来源格真实坐标惯例——沿前例);depth 2 板(D2 熊地精)仅作宿主,行为与敌种无关。
|
||||
func _weaken_refresh_probe() -> Dictionary:
|
||||
func _weaken_accumulate_probe() -> Dictionary:
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
rng.set_master_seed(20260916)
|
||||
var settlement = load("res://core/battle_orchestrator.gd").new(_db, rng)
|
||||
@@ -227,11 +233,24 @@ func _weaken_refresh_probe() -> Dictionary:
|
||||
var src: Dictionary = {"source_class": "mine_hit", "origin_cell": Vector2i(0, 0), "round_index": settlement.round_index}
|
||||
settlement._status_effects.apply_effect("weaken", src)
|
||||
settlement._status_effects.decay_round() # remaining 2 → 1(先兑付后衰减——只借衰减器,不结算)
|
||||
settlement._status_effects.apply_effect("weaken", src) # 续时:remaining ← 2,层数不动
|
||||
settlement._status_effects.apply_effect("weaken", src) # 累加:remaining 1+2=3,层数不动
|
||||
var regrant := _weaken_inst(settlement)
|
||||
settlement._status_effects.apply_effect("weaken", src, 3) # 覆盖时长按覆盖值累加:3+3=6
|
||||
var override_grant := _weaken_inst(settlement)
|
||||
settlement._status_effects.apply_effect("weaken", src) # 同轮再授:6+2=8
|
||||
var extra := _weaken_inst(settlement)
|
||||
if regrant.is_empty() or override_grant.is_empty() or extra.is_empty():
|
||||
return {}
|
||||
# 走伤害控制器公有算术面 clamped_pool
|
||||
return {"layers": int(extra.layers), "pool": int(settlement._damage.clamped_pool("enemy_output")),
|
||||
"after_regrant": int(regrant.remaining_settlements), "after_override": int(override_grant.remaining_settlements),
|
||||
"after_extra": int(extra.remaining_settlements), "snap_magnitude": int(regrant.snap_magnitude)}
|
||||
|
||||
|
||||
func _weaken_inst(settlement: Object) -> Dictionary:
|
||||
for eff in settlement._status_effects.query_active("enemy"):
|
||||
if String(eff.effect_id) == "weaken":
|
||||
# 走伤害控制器公有算术面 clamped_pool
|
||||
return {"layers": int(eff.layers), "remaining": int(eff.remaining_settlements), "pool": int(settlement._damage.clamped_pool("enemy_output"))}
|
||||
return eff
|
||||
return {}
|
||||
|
||||
|
||||
@@ -339,7 +358,7 @@ func _smoke_pool_wiring() -> void:
|
||||
|
||||
|
||||
# 构造停手轮首行主角攻击行:opts = {effects: Array};hero_atk 覆盖 100 拉开量级
|
||||
# (floor 关系可精确断言);效果直授沿 _weaken_refresh_probe 前例。
|
||||
# (floor 关系可精确断言);效果直授沿 _weaken_accumulate_probe 前例。
|
||||
func _hero_attack_row_with(opts: Dictionary, hero_atk_val: int, seed_val: int) -> Dictionary:
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
rng.set_master_seed(seed_val)
|
||||
|
||||
@@ -464,7 +464,8 @@ func _row_phase(row: Dictionary, ri: int) -> int:
|
||||
"damage":
|
||||
return 2 # 案C:全部伤害兑付=战斗段(主角先手/敌方还手/地图账殿后统一结账)
|
||||
"reward_ineffective":
|
||||
return 2 if String(row.get("forfeit", "")) == "hero_down" else 0 # 战斗段末地图账不兑留痕 vs 授予段未生效
|
||||
# 战斗段末地图账行(hero_down 兜底留痕 / deferred 直伤无目标——行载荷自描述键,迭代 48 卡①裁决补记)
|
||||
return 2 if String(row.get("forfeit", "")) == "hero_down" or bool(row.get("deferred", false)) else 0 # 战斗段末地图账不兑留痕 vs 授予段未生效
|
||||
match String(row.get("source_class", "")):
|
||||
"safe_cell", "mine_hit", "seal_hit", "seal_miss", "clear_reward":
|
||||
if int(row.get("round_index", ri)) < ri:
|
||||
|
||||
@@ -269,10 +269,10 @@ func _smoke_ac_swap_guard() -> void:
|
||||
# ① 三处无双轨
|
||||
Kit.check("状态表 defense_up 行已退役(无双轨)", _db.combat.status_effects.row_by_id("defense_up").is_empty())
|
||||
var ac_row: Dictionary = _db.combat.status_effects.row_by_id("ac_up")
|
||||
Kit.check("ac_up 行在位(hero · +1 ac · 只续时不叠层——2026-09-20 主角增益续时批)",
|
||||
Kit.check("ac_up 行在位(hero · +1 ac · 累加语义——同名重复授予加时长不叠层)〔状态累加 V4〕",
|
||||
not ac_row.is_empty() and String(ac_row.get("target_side", "")) == "hero" \
|
||||
and String(ac_row.get("unit", "")) == "ac" and int(ac_row.get("magnitude", 0)) == 1 \
|
||||
and String(ac_row.get("stack_policy", "")) == "refresh")
|
||||
and String(ac_row.get("stack_policy", "")) == "accumulate")
|
||||
var ac_reward := {}
|
||||
for row in _db.run.reward.rows:
|
||||
if String(row.get("cell_type", "")) == "defense" and String(row.get("polarity", "")) == "positive":
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
> 日期:2026-11-01
|
||||
> 性质:需求改动实现批卡片;零待裁点,开工门=U0。
|
||||
> 裁决补记(2026-11-02 用户甲案):round_flow 相位单调断言红=测试分类器对「战斗段地图账未生效行」缺映射(生产行序符合案C)——补记第十一节申报第 5 条+第七节写面两行+第十节 T1 两步;方案=生产行载荷自描述键 `deferred`(零行为改动、观测面扩展),裁决原文见 reports/iter48-停机呈报-卡1状态相位断言-2026-11-02.md。
|
||||
> 来源:待办清单「状态合并改累加制——同名状态重复授予改加时长」条(2026-10-31 用户立案并四点裁决闭合;登记批 git 提交 d216ae04,设计闭合批 870b2f2b)。
|
||||
> 唯一事实源:[增益状态](../design/gdd/systems/战斗循环/增益状态.md) v1.3(2026-10-31)——§同名状态再拿到(合并策略表:叠加/累加/并存)· §剩余次数怎么倒数 · 「幅度与量纲」节盾牌加护行与字段表。本卡只实现上述设计,不改设计。
|
||||
> 估时:T0–T2 ≈ **1.0~1.25 个工作日**(中值 ≈1.125)。
|
||||
@@ -79,6 +80,8 @@
|
||||
| game/tests/unit/battle_settlement/roll_multiplier_test.gd | 掷点/削弱/AC11 套件 | 行为改动(测试面):削弱累加探针换代+新增三条断言(对照表 R2–R4;申报见第十一节) |
|
||||
| game/tests/unit/data_config/table_structure_guard_test.gd | 表结构守卫 | 行为改动(测试面):ac_up 行断言换代(对照表 R1;申报见第十一节) |
|
||||
| game/tests/README.md | 能力清单与覆盖域表 | 写卡段维护件——本卡落位时已入表,实现批零改动 |
|
||||
| game/core/damage_controller.gd `_ineffective_row` | 行载荷加自描述键 `deferred: true`(战斗段地图账未生效行——裁决补记 2026-11-02 甲案) | 非行为改动(观测面扩展,零绘制/结算变化;对照表 R7) |
|
||||
| game/tests/unit/battle_settlement/round_flow_skill_pool_test.gd `_row_phase` | reward_ineffective 分类补 deferred 分支(战斗段)——裁决补记随动(对照表 R7) | 行为改动(测试面,断言判据随申报 5 换代) |
|
||||
|
||||
## 八、落位与可复用性预检
|
||||
|
||||
@@ -107,6 +110,7 @@
|
||||
- [ ] roll_multiplier_test.gd:③段 :157–158 注释与 :160–161 断言换代(重置 2 → 累加 3);`_weaken_refresh_probe` 改名 `_weaken_accumulate_probe`(:159 调用点与 :342 引用注释随改),探针改五段式——授予(2)→衰减(1)→重授(1+2=3,V1)→覆盖值重授(3+3=6,V3)→同轮再授(6+2=8,V2);返回 {layers, pool, after_regrant, after_override, after_extra, snap_magnitude} 六读数(pool 键保留——:163 池读数断言零改动在位)
|
||||
- [ ] 新增断言三条(尾缀〔状态累加 V1/V2/V3〕):V1=重授后 remaining==3、layers==1、snap_magnitude==−65(首授快照恒定);V3=覆盖值累加后 remaining==6;V2=同轮再授后 remaining==8
|
||||
- [ ] table_structure_guard_test.gd:273–275:ac_up 行断言 `stack_policy == "accumulate"`+消息换代(累加语义句)——可核查:断言尾缀〔状态累加 V4〕可 grep、套件绿
|
||||
- [ ] 裁决补记随动(2026-11-02 甲案):`_ineffective_row` 载荷加 `"deferred": true`;`_row_phase` reward_ineffective 分类补 `or bool(row.get("deferred", false))` → 战斗段
|
||||
- [ ] 孤立验证:六套件最窄复跑(roll_multiplier/table_structure_guard/system_contracts/damage_controller/seal_polarity/round_flow_skill_pool——EV 锚套件提前曝红)全绿或按 L3②停机、断言尾缀可 grep
|
||||
|
||||
**T2 产出物落位(0.25 天)**
|
||||
@@ -126,6 +130,7 @@
|
||||
| R4 | 覆盖时长按覆盖值累加 | apply_effect :37 override 入累加臂 | 〔状态累加 V3〕(覆盖值 3 重授 remaining==6) | 单元 | 同上(真实施放链 combat_segment :89 走同口) | remaining 累加覆盖值 | 新增:同名状态合并策略(叠加/累加/并存)与剩余次数语义 |
|
||||
| R5 | 快照纪律不变(首授快照恒定) | 非行为改动——累加臂沿用既有重授不换快照口径,零代码变化 | 〔状态累加 V1〕快照断言(snap_magnitude==−65) | 单元 | 同 R2 | 快照域取值(snap_magnitude) | 新增:同名状态合并策略(叠加/累加/并存)与剩余次数语义 |
|
||||
| R6 | 叠加/并存两臂零变化 | 非行为改动——两臂零代码变化 | damage_controller_test :391+seal_polarity_test :684+system_contracts_test 布尔受理——既有断言零改动复跑即回归证词 | 单元 | 各既有真实入口 | 既有断言零改动 | 既有:系统间契约词表与受理口径:五配方互异/掷点标签成员性/增益布尔受理 |
|
||||
| R7 | 战斗段地图账未生效行归类随动(裁决补记 2026-11-02 甲案) | damage_controller.gd `_ineffective_row` 载荷加 `deferred: true`(非行为改动);round_flow `_row_phase` 分类补 deferred→战斗段 | round_flow_skill_pool_test 相位单调断言(同轮执行且通过——seed 42 轨迹含该行型)+五套件回归 | 单元 | `_run_battle(1,0)` 真实结算流 | 相位分类器按自描述键归类;既有申报 1–4 与 R1–R6 断言零变化 | 既有:战斗屏三区几何与棋盘格边长(该套件承载面)——行载荷观测面扩展不立新能力行 |
|
||||
|
||||
**测试削弱申报**(允许的旧断言改动,全部为语义换代非削弱):
|
||||
|
||||
@@ -133,6 +138,7 @@
|
||||
2. roll_multiplier_test.gd:157–158 注释、:230 探针注释与 :342 探针名引用注释换代(「续时:remaining ← 2」→累加口径;旧函数名 `_weaken_refresh_probe` 全仓清零)。
|
||||
3. table_structure_guard_test.gd:274–275 ac_up 行断言值与消息换代(refresh→accumulate)——同上。
|
||||
4. damage_controller_test.gd:376 断言标签「refresh 政策重复授予受理且层数恒 1(叠层改续时裁决)——池值不变」——行为面累加制下仍绿(层数恒 1、池值不变,断言数值零改动),仅标签文字换代为累加口径。
|
||||
5. **round_flow_skill_pool_test.gd `_row_phase` 分类补 deferred 分支(裁决补记 2026-11-02 用户甲案)**:「每轮行相位单调」断言的相位分类器对「战斗段地图账未生效行」(damage_controller `_ineffective_row` 发射、案C 口径在案)原判第 0 段——累加制改变战斗轨迹后该行型首次在种子 42 轨迹出现致断言红。随动=`_ineffective_row` 行载荷加 `deferred: true` 自描述键(非行为改动)+分类器按键归战斗段(相位 2)。五段全序不变量强度不降:归类的是既有设计口径行型,非放宽任何阈值。裁决原文=reports/iter48-停机呈报-卡1状态相位断言-2026-11-02.md。
|
||||
|
||||
## 十二、异常分级
|
||||
|
||||
|
||||
Reference in new issue
Block a user