class_name GrantSegment extends RefCounted # ① 授予段 Segment(迭代 27 T2——P1-1 结算巨函数拆段;段边界=审计五段〔裁点③甲〕)。 # 职责:结算队列(开格/旗判定/清图)→ 极性路由逐批兑付 + 旗判/军规开单 + round_end 施加 + # 转存收口 + 揭示兑付 + 段界结账。行发射/开单/兑付原语仍归宿主编排器(oc)—— # 本段只搬运时序,零算法改动(🔴 零行为变更契约:同种子完整局输出逐位一致)。 # kind 分派单点化(P1-1 同批):counter_add 五位三行组 / grant_material 三位兑付块 # 收 _apply_counter_hit / _apply_material_hit 两助手(原 :683/:742/:777/:839/:1193 与 # :690/:782/:1217 八处——分支本体逐字保留在助手内)。 var oc: BattleOrchestrator # 宿主(类型标注=段内 := 推断前提;循环类名引用 Godot 4 全局类安全) 宿主(状态/行发射/开单单点仍归其身——段只搬运时序) func _init(host) -> void: oc = host func run(ri: int) -> void: # ① 授予段:结算队列(开格/旗判定/清图)→ 极性路由逐批兑付(伤害形态单据暂存——见 _submit 案C 闸)。 # 判定基线 = 轮末在场旗(发射面已过滤——被挖开的旗已随挖掘擦除零兑付,插旗不可逆批 2026-09-19; # 开格事实不可撤)。 oc._defer_board_damage = true # 案C:授予段伤害单据只暂存不结账(2026-10-06 用户裁——兑付时点=战斗段末) for evt in oc._facts_reveals: if not bool(evt.get("resource", false)): continue # 封锁格(initial 通道)恒无资源——不入账(战斗结算 义务②) var snap = evt.get("reward_snapshot") if not (snap is Dictionary): continue if evt.kind == "safe": if bool(evt.get("dug_under_flag", false)): # 插旗不可逆四情况④(2026-09-19 用户拍板):插安全格再挖开 = 零惩罚零奖励——正向兑付 # 作废(归因行在案);标空判定已随旗擦除自然缺席(被挖的旗不在轮末在场基线)。 oc._emit_row("reward_ineffective", "safe_cell", evt.cell, ri, "奖励作废(插旗格直接挖开——零惩罚零奖励)", 0, {}, "") continue # dig_reveal 发射+施加(内容数据驱动扩展批 T3——桶序固定承载等价: # 乘区收集 → 正向兑付 → 计数器 → 追加产出(深挖)→ 奥术矢。 # 迭代 20 T1——payload 扩三事实:is_edge_cell〔边陲矿工〕/is_blank_zero〔跳格采掘〕/ # new_resource_type〔地质学家——快照 cell_type 首见判定,见后集登记〕) var board_b: BoardData = oc.minesweeper.current_board() var snap_pre = evt.get("reward_snapshot") var ctype := String((snap_pre as Dictionary).get("cell_type", "")) if snap_pre is Dictionary else "" var is_new_type := ctype != "" and not oc._fx_new_resource_types.has(ctype) if is_new_type: oc._fx_new_resource_types[ctype] = true var dr_hits := oc._fx_emit("dig_reveal", {"cell": evt.cell, "round": ri, "is_first_dig_of_battle": not oc._feat_first_dig_used, "terrain_kind": oc._harmful_variants(evt.get("variant_ids", []) as Array), "is_edge_cell": evt.cell.x == 0 or evt.cell.y == 0 or evt.cell.x == board_b.width - 1 or evt.cell.y == board_b.height - 1, "is_blank_zero": board_b.digit_of(evt.cell) == 0, "new_resource_type": is_new_type}) var pos_m := 0 var neg_m := 0 var combo_cap := -1 for h in dr_hits: if String(h.get("kind", "")) != "yield_mult": continue pos_m += int(h.get("mult", 0)) neg_m += int(h.get("cost_mult", 0)) if int(h.get("cap", 0)) > 0: combo_cap = int(h.cap) # 矿脉直觉连击上限 oc._grant_routed(oc._feat_yield_adjust(snap, true, pos_m, neg_m, combo_cap), "positive", "safe_cell", evt.cell, ri, "") # 计数器执行(连击计数——加法族,乘区收集后执行=本格兑付用旧值,与迁移前逐位一致) for h in dr_hits: if String(h.get("kind", "")) == "counter_add": _apply_counter_hit(h) # 揭示效果入队(迭代 20 T1——地质学家/跳格采掘 reveal_tiles 订阅面;授予段末 # _flush_pending_reveals 统一掷格兑付) if not oc._hits_of(dr_hits, "reveal_tiles").is_empty(): oc._fx_enqueue_reveal() # 追加产出(深挖钻头 v2——本格双份制:grant_material 命中=配额内追加第二份;标签随行) for h in dr_hits: if String(h.get("kind", "")) == "grant_material": _apply_material_hit(h, evt.cell, ri) # 奥术矢(魔能共鸣——每战首次开安全格追加魔法矢;任意真族单次生效) var spell_hits: Array[Variant] = oc._hits_of(dr_hits, "spawn_spell") if not spell_hits.is_empty() and not oc._feat_first_dig_used: oc._feat_first_dig_used = true var spell_t := oc._damage.open_ticket(DamageController.KIND_BOARD_TYPED, "feat_first_dig_spell", "奥术矢", "board", int((spell_hits[0] as Dictionary).get("value", 0)), DamageController.TARGET_FRONT_ALIVE, ri, evt.cell, "magic") oc._submit(spell_t, false) elif evt.kind == "mine": # 插旗不可逆四情况②:插雷格再挖开 = 只受挖雷一层惩罚(mine_hit 照常兑付——惊动巢穴), # 标中不发(旗已随挖掘擦除、不入轮末判定基线)。 # mine_hit 发射+施加(内容数据驱动扩展批 T3——桶序固定承载等价: # 减半收集 → 负向兑付〔带减半系数〕→ 反打开单 → 连击清零计数器。 # 迭代 20 T1——发射前移+payload 扩 dug_under_flag〔破封一击〕;新增施加面: # damage_reduce〔安全帽耗层减伤——value_counter 层值,一次清零〕/ heal〔血蜜〕/ # blast_scaled〔陷阱爆发——雷伤×倍率全体敌〕/ bonus_delta〔血税〕/ reveal_tiles〔见血开窍〕) var mine_power := int((snap as Dictionary).get("power", 0)) var mh_hits := oc._fx_emit("mine_hit", {"cell": evt.cell, "round": ri, "damage": mine_power, "dug_under_flag": bool(evt.get("dug_under_flag", false)), "hp_ratio": int(round(100.0 * float(int(oc._enemy_system.hero_unit().get("hp", 0))) / float(maxi(1, int(oc._enemy_system.hero_unit().get("max_hp", 1))))))}) var halve_pct := 0 var mine_reduce := 0 for h in mh_hits: match String(h.get("kind", "")): "damage_mult": halve_pct += int(h.get("value", 0)) "damage_reduce": if h.has("value_counter") and String(h.get("value_counter", "")) != "": mine_reduce += oc._fx.counter(String(h.get("value_counter", ""))) # 安全帽——层值减免 else: mine_reduce += int(h.get("value", 0)) # 背水——定值减免 "heal": var hu_heal: Dictionary[Variant, Variant] = oc._enemy_system.hero_unit() hu_heal["hp"] = mini(int(hu_heal.get("hp", 0)) + int(h.get("value", 0)), maxi(1, int(hu_heal.get("max_hp", 1)))) "bonus_delta": var axis := String(h.get("axis", "")) if oc._fx_bonus_delta.has(axis): oc._fx_bonus_delta[axis] += int(h.get("delta", 0)) "blast_scaled": var blast_v := maxi(int(oc.db.settlement.damage_floor), int(float(mine_power) * float(h.get("mult", 1)))) var bs_t := oc._damage.open_ticket(DamageController.KIND_BOARD_BLAST, "feat_blast_scaled", "陷阱爆发", "board", blast_v, DamageController.TARGET_ALL_ALIVE, ri, evt.cell, "", 0, "", {}) oc._submit(bs_t, false) if mine_reduce > 0: snap["power"] = maxi(0, mine_power - mine_reduce) # 减伤落快照(负向兑付按减后值——安全帽每层减 1) for h in mh_hits: if String(h.get("kind", "")) == "counter_add": _apply_counter_hit(h) if not oc._hits_of(mh_hits, "reveal_tiles").is_empty(): oc._fx_enqueue_reveal() # 见血开窍——每颗雷一次揭示(授予段末统一兑付) oc._grant_routed(oc._feat_yield_adjust(snap, false, 0, 0, -1), "negative", "mine_hit", evt.cell, ri, "", "", halve_pct) for h in mh_hits: if String(h.get("kind", "")) == "open_ticket" and String(h.get("channel", "")) == "reflect": var nct := oc._damage.open_ticket(DamageController.KIND_BOARD_BLAST, "attune_nest_counter", "惊巢反制·反弹", "board", int(h.get("value", 0)), DamageController.TARGET_ALL_ALIVE, ri, evt.cell, "", 0, "", {}) oc._submit(nct, false) # 地形变异 兑付段(授予段尾——触发枚举 on_open:挖开即伤、chain 通道同口径;伤害单据案C 暂存到 # 战斗段末兑付〔2026-10-06 用户裁〕;信息型 hide_number 不进结算——呈现层读取,见 board_view 数字遮蔽; # 雷格恒无变异——布置段排除,双层叠罚不存在;插旗格直挖照吃变异伤害——地形后果同 mine_hit 口径, # 非奖励不作废;吞噬流资源兑付〔荆棘编织/地脉补偿〕中伤害形态行同样经案C闸暂存,非伤害形态照常当场) for evt in oc._facts_reveals: var vids: Array[Variant] = evt.get("variant_ids", []) for vid in vids: var vrow: Dictionary[Variant, Variant] = oc.db.variation.row_by_id(String(vid)) if String(vrow.get("effect", "")) != "flat_damage": continue # 触发词表按 effect 路由:flat_damage=on_open 兑现;hide_number/on_open 外组合 = 数据行新词表未接线(显式忽略面) # 地形变异伤害单据(伤害管线单据化批 2026-09-24)——无类型必中,下限保底在控制器管线内 # 迭代 20 T1——damage_taken 发射前移(单据开立前):damage_reduce〔背水——hp_ratio when # 面〕先收集再按减后值开单;counter_add〔保险丝/石肤〕+ ac_bonus〔石肤〕照常施加; # grant_material〔荆棘/地脉〕移到单据提交后(与迁移前兑付值序一致——收益不因减伤变化) var dt_amount := int(vrow.get("effect_value", 0)) var dt_hits := oc._fx_emit("damage_taken", {"kind": "terrain", "amount": dt_amount, "source": String(vid), "cell": evt.cell, "round": ri, "terrain_kind": String(vid), "hp_ratio": int(round(100.0 * float(int(oc._enemy_system.hero_unit().get("hp", 0))) / float(maxi(1, int(oc._enemy_system.hero_unit().get("max_hp", 1))))))}) for h in dt_hits: match String(h.get("kind", "")): "damage_reduce": dt_amount = maxi(0, dt_amount - int(h.get("value", 0))) "ac_bonus": oc._apply_ac_bonus(h) "counter_add": _apply_counter_hit(h) var vt := oc._damage.open_ticket(DamageController.KIND_BOARD_FLAT_HERO, "地形变异", String(vrow.get("display_name", vid)), "board", \ dt_amount, DamageController.TARGET_HERO, ri, evt.cell, "", 0, "", {"variant_id": String(vid)}) oc._submit(vt, false) for h in dt_hits: if String(h.get("kind", "")) == "grant_material": _apply_material_hit(h, evt.cell, ri) for evt in oc._facts_flags: _judge_flag(evt, ri) # 战旗军规开单段(迭代 12 T3 标旗流——flag_judged 批后统一开单:轮末每面标中旗对最前存活敌 # 结算 board_typed 必中伤害〔复用零新配方;「旗所在巢穴敌」简化为 default_target 最前存活敌—— # 台账披露待追认〕;完美布防=本轮旗批全中(hit>0 且 miss==0)时旗伤 ×mult——全对推理奖励)。 # 伤害单据案C 暂存战斗段末兑付。 # flag_settle 发射+施加(内容数据驱动扩展批 T3——战旗 open_ticket + 完美布防 modify_ticket # 改写窗口:旗伤基值×完美倍率后逐旗开单,与迁移前算序一致) var fs_hits := 0 var fs_misses := 0 for fevt in oc._facts_flags: if bool(fevt.get("hit", false)): fs_hits += 1 else: fs_misses += 1 var fs_fx := oc._fx_emit("flag_settle", {"flags_hit_all": fs_hits > 0 and fs_misses == 0, "flags_count": fs_hits, "round": ri}) var banner_hits: Array[Variant] = [] for h in fs_fx: if String(h.get("kind", "")) == "open_ticket" and String(h.get("channel", "")) == "attack": banner_hits.append(h) if not banner_hits.is_empty(): var strike_value := int((banner_hits[0] as Dictionary).get("value", 0)) var flag_mult := 1 for h in fs_fx: if String(h.get("kind", "")) == "modify_ticket" and String(h.get("mode", "")) == "flag_mult": flag_mult *= maxi(1, int(h.get("value", 1))) if fs_misses == 0 and fs_hits > 0 and flag_mult > 1: strike_value *= flag_mult # 完美布防:同轮全中旗伤倍增(全对推理奖励) for fevt in oc._facts_flags: if not bool(fevt.get("hit", false)): continue var st_t := oc._damage.open_ticket(DamageController.KIND_BOARD_TYPED, "feat_flag_strike", "战旗军规", "board", strike_value, DamageController.TARGET_FRONT_ALIVE, ri, fevt.cell, "normal") oc._submit(st_t, false) # round_end 发射+施加(内容数据驱动扩展批 T3——每轮结算收口:熔火之躯反打单开立〔open_ticket # 即时执行〕+积层清零〔counter_add set〕;整备转蓄力由 finish_round_stop 承载——停手侧 AP 已在 # request_stop 记账,转存决策=grant_ap(mode:transfer) 订阅定夺,无订阅走 RAP 转存缺省) var re_fx := oc._fx_emit("round_end", {"round": ri}) for h in re_fx: if String(h.get("kind", "")) == "open_ticket" and String(h.get("channel", "")) == "blast": var mg_layers := oc._fx.counter(String(h.get("per", ""))) var mg_total := int(h.get("value", 0)) * mg_layers if mg_total > 0: # 迭代 20 T9——source_class 中性名(旧件名 feat_magma_body 随熔火之躯退役;per-counter 反打通道保留泛用面) var mg_t := oc._damage.open_ticket(DamageController.KIND_BOARD_BLAST, "fx_blast_counter", "积层反噬 ×%d" % mg_layers, "board", mg_total, DamageController.TARGET_ALL_ALIVE, ri, oc.minesweeper.hero_pos(), "", 0, "", {}) oc._submit(mg_t, false) for h in re_fx: if String(h.get("kind", "")) == "counter_add": _apply_counter_hit(h) # 迭代 20 T1——round_end 新施加面:grant_gp〔爆破会计/收盘——escrow 战斗域缓冲,随 gp_dropped 上抛〕/ # grant_ap mode:queue〔封印回响——返 1 AP 下轮,queue_ap_delta 通道与轮始加成同面〕 for h in re_fx: if String(h.get("kind", "")) == "grant_gp": oc.escrow += int(h.get("value", 0)) oc._emit_row("effect", "fx_grant_gp", Vector2i(-1, -1), ri, "专长·GP 入账 +%d" % int(h.get("value", 0)), int(h.get("value", 0)), {"effect_id": "fx_grant_gp", "escrow": oc.escrow}, "") elif String(h.get("kind", "")) == "grant_ap" and String(h.get("mode", "")) == "queue": oc.action_economy.queue_ap_delta(int(h.get("value", 0))) # 转存率入参(迭代 22 秘宝批 T3——储备罐 rap_transfer_mult magnitude=目标转存率百分比 125=1.25:1; # 未装配=100 与旧 1:1 逐位一致) var rap_pct: int = oc.attune_param_sum("rap_transfer_mult") oc.action_economy.finish_round_stop(oc._fx != null and oc._fx.has_effect_on("round_end", "grant_ap", "transfer"), rap_pct if rap_pct > 0 else 100) if oc._facts_path == "cleared": oc._grant_clear_reward(ri) oc._flush_pending_reveals(ri) # 迭代 20 T1——揭示效果兑付(授予段末统一掷格,防轮 facts 迭代重入) oc._damage.flush() # 授予段界结账(案C 后本段伤害单据全数暂存,此处对空队 no-op——保留作防御性段界) # 旗判定(迭代 12 T3 标旗流本体随段迁入——原编排器 _judge_flag 逐字搬运,仅宿主引用加前缀; # 唯一调用面=本段 run 的 facts_flags 循环)。 func _judge_flag(evt: Dictionary, ri: int) -> void: var cell: Vector2i = evt.cell if evt.hit: if oc._flag_consumed.has(cell): return # 去重跳过(资格以雷格实例为键——排雷玩法 诚实重复上报的对侧);零明细行 oc._flag_consumed[cell] = true oc._perfect_hit_true += 1 # flag_hit 发射+施加(内容数据驱动扩展批 T3——桶序固定承载等价:殉爆〔T4 秘宝面〕→ # 净化改写 → 图谱额外资源 → 基线兑付) var fh_hits := oc._fx_emit("flag_hit", {"cell": cell, "round": ri, "terrain_kind": oc._harmful_adjacent(cell)}) # 标中殉爆(迭代 11 同调批 T5 → 内容数据驱动扩展批 T4:订阅施加——行 triggers open_ticket # channel blast value_from magnitude;每标中一面旗全体存活敌吃 N 群伤,无类型走 blast 通道。 # 迭代 20 T1——封印爆裂〔迁入专长〕同面消费:行 triggers open_ticket channel blast) for h in oc._hits_of(fh_hits, "open_ticket"): if String(h.get("channel", "")) != "blast": continue var fbt := oc._damage.open_ticket(DamageController.KIND_BOARD_BLAST, "feat_flag_burst", "封印爆裂", "board", int(h.get("value", 0)), DamageController.TARGET_ALL_ALIVE, ri, cell, "", 0, "highlight", {}) oc._submit(fbt, false) # 迭代 20 T1——标中新施加面:counter_add〔血税 标中+1 攻——bonus_delta atk 轴〕/ # ac_bonus〔封印桩 本轮 AC+N〕/ preview_area〔示警烟火 3×3 资源类型预告〕/ # remove_mines〔封印匠 每第 3 次该危险格中立移除——mod_eq 闸在行 when〕。 # (净化工兵 rewrite_board 分支随老 27 件退役摘除——效果类型同批除名,T1 落法 commit 留痕) for h in fh_hits: match String(h.get("kind", "")): "counter_add": _apply_counter_hit(h) "ac_bonus": oc._apply_ac_bonus(h) "bonus_delta": var axis_f := String(h.get("axis", "")) if oc._fx_bonus_delta.has(axis_f): oc._fx_bonus_delta[axis_f] += int(h.get("delta", 0)) "remove_mines": var removed: Array[Variant] = oc.minesweeper.remove_mines_in([cell]) if not removed.is_empty(): oc._emit_row("mine_neutralized", "fx_seal_smith", cell, ri, "封印匠·危险格中立移除", 0, {}, "") "preview_area": var board_p: BoardData = oc.minesweeper.current_board() var types: Array[Variant] = [] for n in board_p.neighbors8(cell): var n_snap = oc._reward_economy.query_full_snapshot(n) if n_snap is Dictionary and not types.has(String((n_snap as Dictionary).get("cell_type", ""))): types.append(String((n_snap as Dictionary).get("cell_type", ""))) if oc.treasure_inventory != null and not types.is_empty(): oc.treasure_inventory.apply_overlay("reward_preview", board_p.neighbors8(cell)) oc._emit_row("fx_preview_area", "", cell, ri, "示警烟火·周围资源类型", 0, {"types": types}, "") # 雷区图谱(迭代 12 T3 标旗流——标中雷额外获得一份格面资源:插旗开始产出对标开格; # 复用 grant 单点,额外兑付走同一 _grant_routed 正向路由) for h in fh_hits: if String(h.get("kind", "")) == "grant_material": _apply_material_hit(h, cell, ri, "flag_hit") var snap = oc._reward_economy.grant(cell) if not (snap is Dictionary): return oc._grant_routed(snap, "positive", "flag_hit", cell, ri, "flag_hit") else: oc._perfect_hit_false += 1 if oc._flag_miss_seen.has(cell): return # 每格实例一次去重(归因行与负向兑付同键——防逐轮惩罚轰炸) oc._flag_miss_seen[cell] = true # 完美保险(迭代 20 T4——本战下一次标错不破坏完美资格:_perfect_hit_false 回退=本次标错 # 对完美谓词无痕;只保一次/件,节点级用完即止) if oc._fx_insurance > 0: oc._fx_insurance -= 1 oc._perfect_hit_false -= 1 oc._emit_row("insurance_used", "", cell, ri, "完美保险·标错豁免", 0, {"left": oc._fx_insurance}, "") var hl := "" if oc._perfect_hit_false == 1: hl = "perfect_broken" # 本板完美谓词已破的归因锚 oc._emit_row("flag_miss", "flag_miss", cell, ri, "标旗未中", 0, {}, hl) # 危险直觉·守挂点(迭代 21 T3——flag_missed 发射:契约 12 触发主语=「当回合发生的标错 # 动作」——去重闸=新旧标错判别器〔后续轮重判旧旗被闸挡回零触发〕;双条件②「结算时旗仍在 # 场」由发射面既有过滤承载〔被挖开的旗已随挖掘擦除零兑付〕;grant_ap mode:queue 下一轮 # 开轮兑现——末轮判出无下一轮=合法作废自动成立〔编排器每战新建,队列不跨战〕;限次=合成行 # adventure 域计数器闸) for h in oc._fx_emit("flag_missed", {"cell": cell, "round": ri}): if String(h.get("kind", "")) == "grant_ap" and String(h.get("mode", "")) == "queue": oc.action_economy.queue_ap_delta(int(h.get("value", 0))) var snap = oc._reward_economy.grant(cell) if not (snap is Dictionary): return oc._grant_routed(snap, "negative", "flag_miss", cell, ri, "") # counter_add 三行组单点(原五位分支本体逐字收拢——kind 分派随段归位 P1-1) func _apply_counter_hit(h: Dictionary) -> void: var set_v = h.get("set", null) oc._fx.counter_add(String(h.get("counter_id", "")), int(h.get("value", 0)) if set_v == null else int(set_v), set_v != null) # grant_material 兑付块单点(原三位分支本体逐字收拢——source_class 两态 safe_cell/flag_hit 由参承载) func _apply_material_hit(h: Dictionary, cell: Vector2i, ri: int, source_class: String = "safe_cell") -> void: var g_snap = oc._reward_economy.grant(cell) if g_snap is Dictionary: oc._grant_routed(g_snap, "positive", source_class, cell, ri, "", String(h.get("label", "")))