fix(battle): 地图伤害账殿后批(案C 2026-10-06 用户裁——「主角先手攻击一次」歧义质询触发)——①结算顺序定死=①授予段兑非伤害账(资源/增益/治疗/行动点/GP/警觉,伤害形态单据暂存不兑)→③战斗段「主角先基础攻击→敌人按生成序逐个还手→地图伤害账殿后」→④衰减→⑤判定;②切片=battle_orchestrator 暂存闸 _defer_board_damage/_deferred_board+_submit 案C分流(sync同闸——清图批一致延后)+_outcome_of(暂存单按「将兑付」回报——完美第二份依据开单时点事实)+授予段四处直提改走闸+战斗段末补提交块(主角死于怪物→暂存单整体不兑逐单留「未生效(主角已倒下)」行 forfeit=hero_down);③文档=战斗结算 v0.26(五段表①③行/授予段节/兑付形态表/结账时机双模式/战斗段节/P0闭环/三分量遗留顺手清+三处普通分量改基础分量)+敌人系统(P0第4步战斗段限定+地图账+死亡来源改述)+地图战斗资源(流程图/负向恒即时节/五步清单)+01-核心循环(「怪物的先手」用词相撞改警觉)+README案C批节+registry两处案C注记+编排器头部注释;④测试=行相位分类器换代(damage恒战斗段/reward_ineffective按forfeit分流)+先手断言收紧(存在或授予段终局→必存在)+新增案C段内序断言(地图账不得先于先手或插入敌方还手中间)——冒烟783/0三闸过+run_all 17套全绿+probe_gate --click全绿+gdd_lint与基线一致;⑤旧行为MC锚全数作废(授予段伤害致死短路先手语义消失),重锚归数值批
This commit is contained in:
1 parent
da157e3f65
commit
58dfb56272
8 files changed
+111
-47
No files matched your search
@@ -14,7 +14,10 @@
|
||||
# 伤害管线单据化批(2026-09-24 用户三裁决,06 台账 148):伤害兑付全部收口 伤害控制器(DamageController
|
||||
# 单点管线)——本类六调用点(主角先手/敌方伤害技/棋盘克制直伤/群伤/反噬/地形变异)退化为开单点
|
||||
# (流程决定何时开单给谁开单;单据怎么算归控制器)。结账时机开关在控制器 policy:IMMEDIATE(A=开单
|
||||
# 即结,逐位等价迁移前行为——回切位)/ SEGMENT(B=攒批到段界 flush:授予段尾〔含清图批前〕+ 战斗段尾)。
|
||||
# 即结,逐位等价迁移前行为——回切位)/ SEGMENT(B=攒批到段界 flush:战斗段尾统一兑现)。
|
||||
# 地图伤害账殿后批(案C 2026-10-06 用户裁——「主角先手」歧义质询触发):授予段不再当场兑付任何伤害——
|
||||
# 全部伤害形态单据经 _submit 暂存闸入 _deferred_board(保授予段事件序),战斗段「主角先手→逐敌还手」后
|
||||
# 补提交统一结账;主角死于敌方还手 → 暂存单整体不兑,逐单留「未生效(主角已倒下)」行(forfeit=hero_down)。
|
||||
# 死亡事件 = 单位容器 unit_died(单位自行宣布)→ 控制器作废该敌未结单据〔死亡即不动手〕/ 主角死终止兑付。
|
||||
# 切片登记:① 事件总线载体 = 直连信号(实现期 ADR 项,provisional)② Waiting 相位刷新通道 2026-09-15 用户拍板整体
|
||||
# 拆除(仅 Active 挖掘期受理)③ 效果行协议 = 授予段逐 grant 行 + 增益/减益段续存实例组合行。
|
||||
@@ -63,6 +66,8 @@ var _facts_reveals: Array[Dictionary] = []
|
||||
var _facts_flags: Array[Dictionary] = []
|
||||
var _facts_path := ""
|
||||
var _settling := false
|
||||
var _defer_board_damage := false # 案C 暂存闸(2026-10-06 用户裁:地图奖励伤害兑付迁战斗段末——怪物还手后)
|
||||
var _deferred_board: Array[Dictionary] = [] # 授予段暂存伤害单据(保授予段事件序;战斗段怪物还手后按序补提交统一结账)
|
||||
var _refresh_used_this_round := 0 # 每轮刷新计数(Active 相位合计,兜底上限 = ActionEconomyTable.refresh_cap_per_round)
|
||||
var _board_seq := 0 # 板序号(本战斗第几张板——快照归因用)
|
||||
var _board_from_midround_refresh := false # 装板 provenance:轮内刷新换来的图 = true(清图奖励守卫——刷新图不发清图奖励)
|
||||
@@ -449,8 +454,9 @@ func _maybe_settle() -> void:
|
||||
|
||||
func _settle() -> void:
|
||||
_settling = true
|
||||
_defer_board_damage = true # 案C:授予段伤害单据只暂存不结账(2026-10-06 用户裁——兑付时点=战斗段末)
|
||||
var ri := round_index
|
||||
# ① 授予段:结算队列(开格/旗判定/清图)→ 极性路由逐批兑付。
|
||||
# ① 授予段:结算队列(开格/旗判定/清图)→ 极性路由逐批兑付(伤害形态单据暂存——见 _submit 案C 闸)。
|
||||
# 判定基线 = 轮末在场旗(发射面已过滤——被挖开的旗已随挖掘擦除零兑付,插旗不可逆批 2026-09-19;
|
||||
# 开格事实不可撤)。
|
||||
for evt in _facts_reveals:
|
||||
@@ -489,7 +495,7 @@ func _settle() -> void:
|
||||
var spell_t := _damage.open_ticket(DamageController.KIND_BOARD_TYPED, "feat_first_dig_spell",
|
||||
"奥术矢", "board", int(_damage.feat_flags.get("spell_value", 0)),
|
||||
DamageController.TARGET_FRONT_ALIVE, ri, evt.cell, "magic")
|
||||
_damage.submit(spell_t)
|
||||
_submit(spell_t, false)
|
||||
# 掘进蓄能计数(迭代 11 同调批 T6——battle 域安全开格计数,每 charge_n 格积 1 点)
|
||||
if _attune_has("dig_charge"):
|
||||
_attune_safe_seen += 1
|
||||
@@ -501,9 +507,10 @@ func _settle() -> void:
|
||||
# 标中不发(旗已随挖掘擦除、不入轮末判定基线)。
|
||||
_grant_routed(_feat_yield_adjust(snap, false), "negative", "mine_hit", evt.cell, ri, "")
|
||||
_feat_combo = 0 # 矿脉直觉连击清零(踩雷断连——「推理密度直接奖励」的对侧)
|
||||
# 地形变异 兑付段(授予段尾——触发枚举 on_open:挖开即伤、chain 通道同口径,轮末结算逐行兑现;
|
||||
# 信息型 hide_number 不进结算——呈现层读取,见 board_view 数字遮蔽;雷格恒无变异——布置段排除,
|
||||
# 双层叠罚不存在;插旗格直挖照吃变异伤害——地形后果同 mine_hit 口径,非奖励不作废)
|
||||
# 地形变异 兑付段(授予段尾——触发枚举 on_open:挖开即伤、chain 通道同口径;伤害单据案C 暂存到
|
||||
# 战斗段末兑付〔2026-10-06 用户裁〕;信息型 hide_number 不进结算——呈现层读取,见 board_view 数字遮蔽;
|
||||
# 雷格恒无变异——布置段排除,双层叠罚不存在;插旗格直挖照吃变异伤害——地形后果同 mine_hit 口径,
|
||||
# 非奖励不作废;吞噬流资源兑付〔荆棘编织/地脉补偿〕中伤害形态行同样经案C闸暂存,非伤害形态照常当场)
|
||||
for evt in _facts_reveals:
|
||||
var vids: Array = evt.get("variant_ids", [])
|
||||
for vid in vids:
|
||||
@@ -513,7 +520,7 @@ func _settle() -> void:
|
||||
# 地形变异伤害单据(伤害管线单据化批 2026-09-24)——无类型必中,下限保底在控制器管线内
|
||||
var vt := _damage.open_ticket(DamageController.KIND_BOARD_FLAT_HERO, "地形变异", String(vrow.get("display_name", vid)), "board", \
|
||||
int(vrow.get("effect_value", 0)), DamageController.TARGET_HERO, ri, evt.cell, "", 0, "", {"variant_id": String(vid)})
|
||||
_damage.submit(vt)
|
||||
_submit(vt, false)
|
||||
# 吞噬流四面(迭代 12 T6——地形从纯税到第三资源带;伤害仍发生=乙稿判据 3 承载):
|
||||
# ①荆棘编织者=挖开伤害型地形格额外掉落一次格面资源(主动吃地形换资源)
|
||||
if int(_damage.feat_flags.get("terrain_dig_double", 0)) > 0:
|
||||
@@ -533,7 +540,7 @@ func _settle() -> void:
|
||||
# 战旗军规开单段(迭代 12 T3 标旗流——flag_judged 批后统一开单:轮末每面标中旗对最前存活敌
|
||||
# 结算 board_typed 必中伤害〔复用零新配方;「旗所在巢穴敌」简化为 default_target 最前存活敌——
|
||||
# 台账披露待追认〕;完美布防=本轮旗批全中(hit>0 且 miss==0)时旗伤 ×mult——全对推理奖励)。
|
||||
# 扫雷结算触发点=flag_strike/flag_all_hit/nest_aura 挂点承载红线①。
|
||||
# 扫雷结算触发点=flag_strike/flag_all_hit/nest_aura 挂点承载红线①;伤害单据案C 暂存战斗段末兑付。
|
||||
if int(_damage.feat_flags.get("flag_strike_value", 0)) > 0:
|
||||
var hits := 0
|
||||
var misses := 0
|
||||
@@ -553,23 +560,23 @@ func _settle() -> void:
|
||||
var st_t := _damage.open_ticket(DamageController.KIND_BOARD_TYPED, "feat_flag_strike",
|
||||
"战旗军规", "board", strike_value, DamageController.TARGET_FRONT_ALIVE, ri,
|
||||
fevt.cell, "normal")
|
||||
_damage.submit(st_t)
|
||||
# 熔火之躯轮末反打(迭代 12 T6 吞噬流——受地形伤积层,轮末每层对全体敌 ~1 必中反伤;
|
||||
# 触发键=「受地形伤」通用不按地形种类特化——定稿红线承载;反打后清零)
|
||||
_submit(st_t, false)
|
||||
# 熔火之躯轮末反打(迭代 12 T6 吞噬流——受地形伤积层,对全体敌 ~1 必中反伤;
|
||||
# 触发键=「受地形伤」通用不按地形种类特化——定稿红线承载;反打后清零;单据案C 暂存战斗段末)
|
||||
var magma := int(_damage.feat_flags.get("variant_counter_value", 0))
|
||||
if magma > 0 and _feat_magma_layers > 0:
|
||||
var mg_t := _damage.open_ticket(DamageController.KIND_BOARD_BLAST, "feat_magma_body",
|
||||
"熔火反噬 ×%d" % _feat_magma_layers, "board", magma * _feat_magma_layers,
|
||||
DamageController.TARGET_ALL_ALIVE, ri, minesweeper.hero_pos(), "", 0, "", {})
|
||||
_damage.submit(mg_t)
|
||||
_submit(mg_t, false)
|
||||
_feat_magma_layers = 0
|
||||
if _facts_path == "cleared":
|
||||
_grant_clear_reward(ri)
|
||||
_damage.flush() # 授予段界结账(B 模式——段内开单攒批到此统一兑现;A 模式 no-op;清图批前另有同步结账点)
|
||||
_damage.flush() # 授予段界结账(案C 后本段伤害单据全数暂存,此处对空队 no-op——保留作防御性段界)
|
||||
# ② 增益/减益段(续存实例组合行;本结算新授予的已在授予段逐 grant 出行——增益状态 义务⑦)
|
||||
_emit_composition_effects("hero", ri)
|
||||
_emit_composition_effects("enemy", ri)
|
||||
# ③ 战斗段(调用序:掷点判定 → apply_damage → commit_action;hero hp=0 短路)
|
||||
# ③ 战斗段(调用序:主角先手 → 逐敌还手 → 地图伤害账殿后〔案C 2026-10-06 用户裁〕;hero hp=0 短路)
|
||||
_combat_segment(ri)
|
||||
# ④ 衰减段(恰一次恒执行含末轮——先兑付后衰减)
|
||||
var k: int = _status_effects.decay_round()
|
||||
@@ -775,7 +782,7 @@ func _apply_flat_row(row: Dictionary, source_class: String, cell: Vector2i, ri:
|
||||
if ctype == "blast":
|
||||
var t := _damage.open_ticket(DamageController.KIND_BOARD_BLAST, source_class, display, "board", power, \
|
||||
DamageController.TARGET_ALL_ALIVE, ri, cell, "", 0, highlight, {"batch_key": String(row.reward_id)})
|
||||
return _damage.outcome(_submit(t, sync))
|
||||
return _outcome_of(_submit(t, sync))
|
||||
if ctype == "pierce" or ctype == "magic":
|
||||
# 伤害道具批(2026-09-18)语义不变:正向 = 单目标克制直伤(必中全额不掷点——棋盘来源伤害既有口径);
|
||||
# 负向 = 主角直伤(复用反噬通道)。
|
||||
@@ -784,7 +791,7 @@ func _apply_flat_row(row: Dictionary, source_class: String, cell: Vector2i, ri:
|
||||
var atk_type: String = String(row.get("attack_type", ctype))
|
||||
var t2 := _damage.open_ticket(DamageController.KIND_BOARD_TYPED, source_class, display, "board", power, \
|
||||
DamageController.TARGET_FRONT_ALIVE, ri, cell, atk_type, 0, highlight, {"batch_key": String(row.reward_id)})
|
||||
return _damage.outcome(_submit(t2, sync))
|
||||
return _outcome_of(_submit(t2, sync))
|
||||
if ctype == "heal":
|
||||
if String(row.get("polarity", "positive")) == "negative":
|
||||
return _submit_flat_hero(source_class, display, power, cell, ri, highlight, sync)
|
||||
@@ -805,14 +812,23 @@ func _apply_flat_row(row: Dictionary, source_class: String, cell: Vector2i, ri:
|
||||
# 开单分流:sync(清图批)走控制器同步开单——先按序结清段内排队单据、再当场兑现本单;
|
||||
# 常规开单按结账时机政策(A 即结 / B 入队)。
|
||||
func _submit(t: Dictionary, sync: bool) -> int:
|
||||
if _defer_board_damage:
|
||||
_deferred_board.append(t) # 案C:授予段伤害单据暂存——战斗段怪物还手后按事件序补提交(sync 同闸,清图批一致延后)
|
||||
return -1
|
||||
return _damage.flush_submit(t) if sync else _damage.submit(t)
|
||||
|
||||
|
||||
# 案C 结账读数:暂存单(_submit 返回 -1)以「将兑付」回报——授予段兑付决策(清图完美第二份等)只能
|
||||
# 依据开单时点事实(该时点敌人存活有保证);战斗段末实际结账若目标已灭,控制器自记未生效行。
|
||||
func _outcome_of(ticket_id: int) -> String:
|
||||
return "redeemed" if ticket_id < 0 else _damage.outcome(ticket_id)
|
||||
|
||||
|
||||
# 主角直伤单据(反噬/治疗包负向——无类型必中,下限保底在控制器管线内)
|
||||
func _submit_flat_hero(source_class: String, display: String, power: int, cell: Vector2i, ri: int, highlight: String, sync := false) -> String:
|
||||
var t := _damage.open_ticket(DamageController.KIND_BOARD_FLAT_HERO, source_class, display, "board", power, \
|
||||
DamageController.TARGET_HERO, ri, cell, "", 0, highlight, {})
|
||||
return _damage.outcome(_submit(t, sync))
|
||||
return _outcome_of(_submit(t, sync))
|
||||
|
||||
|
||||
# 旗判定批:标中 = 该雷格资源的正向兑付(每雷实例一次;高光 = 强制检查点);
|
||||
@@ -942,6 +958,7 @@ func _roll_round_actions() -> void:
|
||||
# 停开(B 模式下若 flush 中主角倒下,由控制器死亡事件终止余单——两模式同一结果)。
|
||||
|
||||
func _combat_segment(ri: int) -> void:
|
||||
_defer_board_damage = false # 案C 闸复位——战斗段起开单即入队(主角/敌方/补提交的地图单按开单序统一结账)
|
||||
# 本轮扫雷事实推导(迭代 12 T4——执拗 streak/连珠矢段数共用取数面):本轮 safe 事件数=
|
||||
# streak;踩雷即清零(mine_hit 监听同口——执拗「踩雷清零」承载)。攻击在战斗段=授予段后
|
||||
# 同一次 _settle 内,facts 已定。
|
||||
@@ -956,7 +973,8 @@ func _combat_segment(ri: int) -> void:
|
||||
# 蓄力层注入(迭代 12 T5——整备军备「每层下轮首段 +1」/厚积薄发满层 spike/铁壁整备减伤——
|
||||
# 三件同读 action_economy.charge_layers;battle 域每轮刷新)
|
||||
_damage.feat_flags["charge_layers"] = action_economy.charge_layers
|
||||
# ⓪ 主角先手攻击(基础攻击恒存在——2026-09-11 用户裁决;先于敌方行动;授予段负向直伤致死 → 致电短路不先手)。
|
||||
# ⓪ 主角先手攻击(基础攻击恒存在——2026-09-11 用户裁决;先于敌方行动。案C 后授予段不再产出伤害,
|
||||
# 主角进入战斗段时恒存活——先手必兑,除非场上无敌)。
|
||||
# 单分量伤害构成(2026-09-19 充能退役批·用户拍板):主角攻击 = 唯一基础分量(atk,吃掷点含暴击;
|
||||
# 类型 = 主角 attack_type 表值——2026-09-18 营地扩展前置批:量与类型抽象分离;查甲效矩阵对应行取克制修正)。
|
||||
# 原"基础 + 穿刺/魔法充能三分量"模型随充能系统整体退役——克制策略归冒险前配置(营地换型 / 未来冒险前参数面),
|
||||
@@ -1010,7 +1028,18 @@ func _combat_segment(ri: int) -> void:
|
||||
et["source_unit"] = u
|
||||
et["context"] = {"skill_id": skill_id, "baseline": baseline}
|
||||
_damage.submit(et)
|
||||
_damage.flush() # 战斗段界结账(B 模式——段内开单攒批到此统一兑现;A 模式 no-op)
|
||||
# 地图伤害兑付(案C 2026-10-06 用户裁——战斗段末:怪物还手后按授予段事件序补提交统一结账;
|
||||
# 主角死于怪物 → 地图账不兑,逐单留「未生效」行不作废静默——没生效也要留痕口径;
|
||||
# 补提交后若地图直伤反杀主角,控制器 _halted 作废余单——战斗已败,胜负归判定段)
|
||||
if int(_enemy_system.hero_unit().get("hp", 0)) <= 0:
|
||||
for t in _deferred_board:
|
||||
_emit_row("reward_ineffective", String(t.get("source_class", "")), t.get("origin_cell", Vector2i(-1, -1)), ri,
|
||||
"%s 未生效(主角已倒下)" % String(t.get("display", "")), 0, {"forfeit": "hero_down"}, "")
|
||||
else:
|
||||
for t in _deferred_board:
|
||||
_damage.submit(t)
|
||||
_deferred_board.clear()
|
||||
_damage.flush() # 战斗段界结账(B 模式——主角单+敌方单+地图单按开单序统一兑现;A 模式地图单补提交时即结)
|
||||
|
||||
|
||||
# ---- 算术读数(伤害管线单据化批 2026-09-24 迁移注记)----
|
||||
|
||||
Reference in new issue
Block a user