Files
gplan-2/game/core/settlement/combat_segment.gd
T
DKChan cc02bb9315 卡①T1+T2(拆件批wr1/wr2/wr3): BattleFxHost+RewardGrant两新件建件+fx/grant族迁移+use_treasure拆分+三触点分家——battle_fx_host.gd(14类变量:bundle7+grant_cb+engine+counters_ctx+ac/reveal两束;fx_emit/emit_round_start/apply_ac_bonus/enqueue_reveal/flush_pending_reveals取号序逐字/rebuild_subscriptions/mount_buckets/reset_battle_state/bonus_delta_drain/reveal_busy)+reward_grant.gd(15类变量:bundle11+escrow+defer+treasure_inventory+battle_ledger;grant_routed随att归因束改形/submit案C闸/use_treasure四步骨架+_charge_gate+_apply_use_kinds+_safe_dig_open+_cell_removal_open/grant_clear_reward三参形宿主态经参传入/reveal_redeem兑付回调面);宿主删fx族11成员+grant族3成员,组件出口fx_host()/reward_grant(),_fx_host_fact五事实单点+_attune_safe_seen_read读投影,treasure_inventory带setter转发,begin_battle七接线点改指,_battle_over改bonus_delta_drain,_roll_gp_drop读_reward_grant.escrow;两段三引用构造(与T4接口块同形先行)读写面改指(oc._submit实为7处G5清单漏1,oc._fx_bonus_delta axis/axis_f两形);treasure_interact_controller改ctx束8键+三现值同查+inventory_projection拆_projection_row/_auto_row;main_ui_build构造改束(grant_get=run_scope.settlement.reward_grant()现值);S7/S8登记两新件7→9;测试改址:adventure_feats 75+round_flow 8+treasure_effects 7(含G11漏载的ctrl4构造点)+settle_segments 3+seal_polarity 10(含G11漏载的_grant_clear_identity直调)+level_shop 4+forge 2,另修reward_grant内部_submit/_outcome_of旧名三处与adventure_feats orch._fx/orch0._fx.rebuild两残漏(脚本错误静默吞断言假绿形态,修后feats 138PASS/seal 73PASS恢复全额);代拍板:①RewardGrant bundle 12→11键(minesweeper改经fx_host同源引用)腾位battle_ledger独立成员(卡面15≤15算术缺口,16键=基线外NEW停卡不可取)②bind_grant落_reward_grant.reveal_redeem(query_full_snapshot唯授予件持有,D1「RewardGrant授予面」兑付回调口径)③续拆四私有(迁入形逐键过阈值义务)④grant_clear_reward测试改址传宿主态读(s._board_from_midround_refresh/perfect_sweep_earned)。验收:七套件直跑绿+零SCRIPT ERROR+gdstyle基线外新违规0(battle_orchestrator行数恶化键随拆件归绿989<1302;level_map_screen 22>21=iter38存量漏登记非本批触碰面)〔拆件批 V8〕
2026-10-27 06:07:15 +08:00

105 lines
7.8 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
class_name CombatSegment
extends RefCounted
# ③ 战斗段 Segment(P1-1 结算巨函数拆段;段边界=审计五段〔裁点③甲〕)。
# 职责:案C 闸复位 + 本轮扫雷事实推导(执拗 streak/连珠矢段数)+ 蓄力层注入 + 主角先手
# (含连珠矢分段开单)+ 敌方行动兑现 + 地图伤害账殿后(补提交统一结账)。
# 调用序:主角先手 → 逐敌还手 → 地图伤害账殿后〔案C〕;hero hp=0 短路。
# 行发射/开单单点归宿主(oc)——案C 暂存闸归 RewardGrant(段持三引用直调,零转发壳)——
# 本函数体为原编排器 _combat_segment 逐字搬运(🔴 零行为变更契约)。
var oc: BattleOrchestrator # 宿主(类型标注=段内 := 推断前提;循环类名引用 Godot 4 全局类安全)
var fx_host: BattleFxHost # 效果引擎宿主件(三引用构造——本轮无消费面,构造形与授予段同形)
var reward_grant: RewardGrant # 奖励授予件(案C 暂存闸 defer 持有方)
func _init(host, fx_host_ref: BattleFxHost, reward_grant_ref: RewardGrant) -> void:
oc = host
fx_host = fx_host_ref
reward_grant = reward_grant_ref
func run(ri: int) -> void:
reward_grant.defer["on"] = false # 案C 闸复位——战斗段起开单即入队(主角/敌方/补提交的地图单按开单序统一结账)
# 本轮扫雷事实推导(执拗 streak/连珠矢段数共用取数面):本轮 safe 事件数=
# streak;踩雷即清零(mine_hit 监听同口——执拗「踩雷清零」承载)。攻击在战斗段=授予段后
# 同一次 _settle 内,facts 已定。
var round_safe := 0
var round_mine := false
for evt in oc._facts_reveals:
if evt.kind == "safe":
round_safe += 1
elif evt.kind == "mine":
round_mine = true
oc._damage.dig_streak = 0 if round_mine else round_safe
# 蓄力层注入(内容数据驱动扩展批 T3——整备军备「每层下轮首段 +1」/厚积薄发满层 spike/铁壁整备
# 减伤——三件 fact charge_layers 同读 action_economy;battle 域每轮刷新)
oc._damage.charge_layers = oc.action_economy.charge_layers
# ⓪ 主角先手攻击(基础攻击恒存在;先于敌方行动。案C:授予段不再产出伤害,
# 主角进入战斗段时恒存活——先手必兑,除非场上无敌)。
# 单分量伤害构成:主角攻击 = 唯一基础分量(atk,吃掷点含暴击;
# 类型 = 主角 attack_type 表值(量与类型抽象分离);查甲效矩阵对应行取克制修正)。
# 原"基础 + 穿刺/魔法充能三分量"模型随充能系统整体退役——克制策略归冒险前配置(营地换型 / 未来冒险前参数面),
# 局内不再有挖掘攒弹药的第二伤害供给。attack_up 增益经 hero_offense 池乘攻击合计(见池乘区注记)。
# 护甲等级掷点:基础分量吃掷点判定(含暴击);棋盘来源伤害不掷不折;
# 任何伤害落地 ≥ damage_floor(全局 max(1,·) 适用所有来源,下限在控制器管线单点收口)。
var hero_alive: bool = int(oc._enemy_system.hero_unit().get("hp", 0)) > 0
var hero_target = oc._enemy_system.default_target()
if hero_alive and hero_target != null:
var ht := oc._damage.open_ticket(DamageController.KIND_HERO_ATTACK, "hero_attack", "主角攻击", "combat", oc._hero_atk, \
DamageController.TARGET_FRONT_ALIVE, ri, Vector2i(-1, -1), String(oc._enemy_system.hero_unit().get("attack_type", "normal")))
oc._damage.submit(ht)
# 连珠矢(内容数据驱动扩展批 T3——attack_commit 订阅施加面:开格节奏变攻击段数,本轮每开
# ~3 安全格 +1 段穿刺附加(上限 cap;段值 provisional 固定值不乘 atk——台账披露)。施加位
# 紧随主角攻击单开立=迁移前开单位(先于敌方行动单入队——flush 兑现序逐位一致)
for h in oc._hits_of(ht.context.get("fx_attack_hits", []) as Array, "attack_segments"):
var segments := mini(int(h.get("cap", 2)), oc._damage.dig_streak / maxi(1, int(h.get("divisor", 3))))
for s in segments:
# source_class 用中性名;attack_segments 兑付通道保留泛用面
var ct := oc._damage.open_ticket(DamageController.KIND_BOARD_TYPED, "fx_streak_segments",
"连击分段", "board", int(h.get("value", 0)), DamageController.TARGET_FRONT_ALIVE, ri,
oc.minesweeper.hero_pos(), "pierce")
oc._damage.submit(ct)
# 敌方行动(敌人技能池批——本拍动作开轮已摇定,此处按技能行兑现;行序 = 生成序)。
# 死亡即不动手:摇定后、兑现前死亡的敌不在存活序中——本拍技能作废,不 commit、不进冷却。
for u in oc._enemy_system.query_alive("enemy"):
if int(oc._enemy_system.hero_unit().hp) <= 0:
break # hero hp=0 立即短路(死尸挨打行是归因噪音——用户拍板)
var skill_id := oc._enemy_system.pending_action(u)
var srow: Dictionary[Variant, Variant] = oc.db.skill_row(skill_id)
if srow.is_empty():
oc._fatal("敌实例待发动作悬空: %s" % skill_id)
continue
if String(srow.type) == "buff" or String(srow.type) == "debuff":
# 增益/妨害技 = 0 伤害施放行:不掷不折;状态授予即数值兑现,技能冷却与增益持续两计时器分账。
# 落点由状态行 target_side 路由(buff → 敌方侧 / debuff → 主角侧——容器零改动,proposal-status-vocabulary §1)。
var dur: int = int(srow.get("buff_duration", 1))
oc._status_effects.apply_effect(String(srow.buff_ref), {"source_class": "enemy_action", "origin_cell": Vector2i(-1, -1), "round_index": ri}, dur)
oc._emit_row("cast", "enemy_action", Vector2i(-1, -1), ri, "%s 施放 %s" % [u.display_name, String(srow.display_name)], 0, {"skill_id": skill_id, "effect_id": String(srow.buff_ref), "duration": dur})
oc._enemy_system.commit_action(u)
continue
# 伤害技(含普攻——倍率恒 1)= 敌方伤害技单据:基线 = round(atk×倍率)、rider 预计算归开单侧
# (表值算术零随机),掷点/克制查表(第 9 参 = 敌方 attack_type——迭代 24 N3 轴开列前恒空串不查表)/
# hero_defense×enemy_output 池乘区/下限/rider 后置/commit 全归控制器管线(兑现序 = 开单序;
# 来源敌已死在兑现时作废——死亡即不动手)。
var baseline: int = int(round(float(u.atk) * float(srow.get("damage_mult", 1.0))))
var rider := 0
if srow.has("rider_mult"):
rider = maxi(int(oc.db.settlement.damage_floor), int(floor(float(u.atk) * float(srow.rider_mult))))
var et := oc._damage.open_ticket(DamageController.KIND_ENEMY_SKILL, "enemy_action", "%s %s" % [u.display_name, String(srow.display_name)], "combat", \
baseline, DamageController.TARGET_HERO, ri, Vector2i(-1, -1), String(u.get("attack_type", "normal")), rider)
et["source_unit"] = u
et["context"] = {"skill_id": skill_id, "baseline": baseline}
oc._damage.submit(et)
# 地图伤害兑付(案C:战斗段末——怪物还手后按授予段事件序补提交统一结账;
# 主角死于怪物 → 地图账不兑,逐单留「未生效」行不作废静默——没生效也要留痕口径;
# 补提交后若地图直伤反杀主角,控制器 _halted 作废余单——战斗已败,胜负归判定段)
if int(oc._enemy_system.hero_unit().get("hp", 0)) <= 0:
for t in (reward_grant.defer["queue"] as Array):
oc._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 (reward_grant.defer["queue"] as Array):
oc._damage.submit(t)
(reward_grant.defer["queue"] as Array).clear()
oc._damage.flush() # 战斗段界结账(B 模式——主角单+敌方单+地图单按开单序统一兑现;A 模式地图单补提交时即结)