iter44-卡2:卡②(战斗编排归约批): RoundCycle+BattleFacts两新件·宿主38→15·treasure_inventory经reward_grant()出口直注·_hero_atk派生读·完美账三mark写口·behavior_roll流随件迁移取号序逐字·对照表V1-V5新增断言内嵌·键账15/15/8·811行
This commit is contained in:
1 parent
5a1ddb65e6
commit
3465b932ce
18 files changed
+346
-260
No files matched your search
@@ -26,7 +26,7 @@ func run(ri: int) -> void:
|
||||
# 同一次 _settle 内,facts 已定。
|
||||
var round_safe := 0
|
||||
var round_mine := false
|
||||
for evt in oc._facts_reveals:
|
||||
for evt in oc._facts.reveals:
|
||||
if evt.kind == "safe":
|
||||
round_safe += 1
|
||||
elif evt.kind == "mine":
|
||||
@@ -53,7 +53,7 @@ func _hero_strike(ri: int) -> void:
|
||||
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", "主角攻击",
|
||||
{"channel": "combat", "base_value": oc._hero_atk, "target_rule": DamageController.TARGET_FRONT_ALIVE,
|
||||
{"channel": "combat", "base_value": oc._hero_atk(), "target_rule": DamageController.TARGET_FRONT_ALIVE,
|
||||
"ri": ri, "origin_cell": Vector2i(-1, -1),
|
||||
"attack_type": String(oc._enemy_system.hero_unit().get("attack_type", "normal"))})
|
||||
oc._damage.submit(ht)
|
||||
|
||||
@@ -34,7 +34,7 @@ func run(ri: int) -> void:
|
||||
|
||||
# 开格/踩雷兑付批(轮 facts_reveals 资源事件序:safe 正向乘区兑付 / mine_hit 减半负向兑付)
|
||||
func _reveal_batch(ri: int) -> void:
|
||||
for evt in oc._facts_reveals:
|
||||
for evt in oc._facts.reveals:
|
||||
if not bool(evt.get("resource", false)):
|
||||
continue # 封锁格(initial 通道)恒无资源——不入账(战斗结算 义务②)
|
||||
var snap = evt.get("reward_snapshot")
|
||||
@@ -61,7 +61,7 @@ func _reveal_safe(evt: Dictionary, snap: Dictionary, ri: int) -> void:
|
||||
if is_new_type:
|
||||
fx_host._fx_new_resource_types[ctype] = true
|
||||
var dr_hits := fx_host.fx_emit("dig_reveal", {"cell": evt.cell, "round": ri,
|
||||
"is_first_dig_of_battle": not oc._feat_first_dig_used,
|
||||
"is_first_dig_of_battle": not oc._facts.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,
|
||||
@@ -91,8 +91,8 @@ func _reveal_safe_apply(dr_hits: Array, evt: Dictionary, ri: int) -> void:
|
||||
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
|
||||
if not spell_hits.is_empty() and not oc._facts.feat_first_dig_used:
|
||||
oc._facts.feat_first_dig_used = true
|
||||
var spell_t := oc._damage.open_ticket(DamageController.KIND_BOARD_TYPED, "feat_first_dig_spell", "奥术矢",
|
||||
{"channel": "board", "base_value": int((spell_hits[0] as Dictionary).get("value", 0)),
|
||||
"target_rule": DamageController.TARGET_FRONT_ALIVE, "ri": ri, "origin_cell": evt.cell, "attack_type": "magic"})
|
||||
@@ -160,7 +160,7 @@ func _reveal_mine_apply(mh_hits: Array, snap: Dictionary, cell: Vector2i, ri: in
|
||||
# 危险格恒无变异——布置段排除,双层叠罚不存在;封印格直挖照吃变异伤害——地形后果同 mine_hit 口径,
|
||||
# 非奖励不作废;吞噬流资源兑付〔荆棘编织/地脉补偿〕中伤害形态行同样经案C闸暂存,非伤害形态照常当场)
|
||||
func _terrain_batch(ri: int) -> void:
|
||||
for evt in oc._facts_reveals:
|
||||
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.combat.variation.row_by_id(String(vid))
|
||||
@@ -203,7 +203,7 @@ func _terrain_damage_reduce(dt_hits: Array, dt_amount: int) -> int:
|
||||
# 台账披露待追认〕;完美布防=本轮封印批全中(hit>0 且 miss==0)时封印伤 ×mult——全对推理奖励)。
|
||||
# 伤害单据案C 暂存战斗段末兑付。
|
||||
func _seal_batch(ri: int) -> void:
|
||||
for evt in oc._facts_seals:
|
||||
for evt in oc._facts.seals:
|
||||
_judge_seal(evt, ri)
|
||||
_seal_strike_batch(ri)
|
||||
|
||||
@@ -213,7 +213,7 @@ func _seal_batch(ri: int) -> void:
|
||||
func _seal_strike_batch(ri: int) -> void:
|
||||
var fs_hits := 0
|
||||
var fs_misses := 0
|
||||
for fevt in oc._facts_seals:
|
||||
for fevt in oc._facts.seals:
|
||||
if bool(fevt.get("hit", false)):
|
||||
fs_hits += 1
|
||||
else:
|
||||
@@ -223,7 +223,7 @@ func _seal_strike_batch(ri: int) -> void:
|
||||
var strike := _seal_strike_value(fs_fx, fs_hits, fs_misses)
|
||||
if strike.is_empty():
|
||||
return
|
||||
for fevt in oc._facts_seals:
|
||||
for fevt in oc._facts.seals:
|
||||
if not bool(fevt.get("hit", false)):
|
||||
continue
|
||||
var st_t := oc._damage.open_ticket(DamageController.KIND_BOARD_TYPED, "feat_seal_strike", "战封印军规",
|
||||
@@ -272,8 +272,8 @@ func _round_end_apply(ri: int) -> void:
|
||||
var rap_pct: int = oc.attune_param_sum("rap_transfer_mult")
|
||||
oc.action_economy.finish_round_stop(fx_host.engine.has_effect_on("round_end", "grant_ap", "transfer"),
|
||||
rap_pct if rap_pct > 0 else 100)
|
||||
if oc._facts_path == "cleared":
|
||||
reward_grant.grant_clear_reward(ri, oc._board_from_midround_refresh, oc.perfect_sweep_earned())
|
||||
if oc._facts.path == "cleared":
|
||||
reward_grant.grant_clear_reward(ri, oc._facts.board_from_midround, oc.perfect_sweep_earned())
|
||||
fx_host.flush_pending_reveals(ri) # 揭示效果兑付(授予段末统一掷格,防轮 facts 迭代重入)
|
||||
oc._damage.flush() # 授予段界结账(案C 后本段伤害单据全数暂存,此处对空队 no-op——保留作防御性段界)
|
||||
|
||||
@@ -305,10 +305,10 @@ func _judge_seal(evt: Dictionary, ri: int) -> void:
|
||||
# 殉爆票据 → 施加面 → 雷区图谱额外兑付 → 基线正向兑付)
|
||||
func _judge_seal_hit(evt: Dictionary, ri: int) -> void:
|
||||
var cell: Vector2i = evt.cell
|
||||
if oc._seal_consumed.has(cell):
|
||||
if oc._facts.seal_consumed.has(cell):
|
||||
return # 去重跳过;零明细行
|
||||
oc._seal_consumed[cell] = true
|
||||
oc._perfect_hit_true += 1
|
||||
oc._facts.seal_consumed[cell] = true
|
||||
oc._facts.mark_perfect_hit()
|
||||
var fh_hits := fx_host.fx_emit("seal_hit", {"cell": cell, "round": ri,
|
||||
"terrain_kind": oc._harmful_adjacent(cell)})
|
||||
_seal_burst_tickets(fh_hits, cell, ri)
|
||||
@@ -367,8 +367,8 @@ func _seal_preview_area(cell: Vector2i, ri: int) -> void:
|
||||
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))
|
||||
if reward_grant.treasure_inventory != null and not types.is_empty():
|
||||
reward_grant.treasure_inventory.apply_overlay("reward_preview", board_p.neighbors8(cell))
|
||||
oc._emit_row({"type": "extended", "source_class": "fx_warning_beacon", "origin_cell": cell}, ri, "示警烟火·周围资源类型", 0, {"effect_id": "fx_preview_area", "types": types})
|
||||
|
||||
|
||||
@@ -376,10 +376,10 @@ func _seal_preview_area(cell: Vector2i, ri: int) -> void:
|
||||
# grant_ap mode:queue 下一轮兑现 / forgive_seal_miss 完美保险豁免 → 归因行 → 负向兑付)
|
||||
func _judge_seal_miss(evt: Dictionary, ri: int) -> void:
|
||||
var cell: Vector2i = evt.cell
|
||||
oc._perfect_hit_false += 1
|
||||
if oc._seal_miss_seen.has(cell):
|
||||
oc._facts.mark_perfect_miss()
|
||||
if oc._facts.seal_miss_seen.has(cell):
|
||||
return # 每格实例一次去重
|
||||
oc._seal_miss_seen[cell] = true
|
||||
oc._facts.seal_miss_seen[cell] = true
|
||||
# 危险直觉·守挂点(seal_missed 发射:契约 12 触发主语=「当回合发生的标错
|
||||
# 动作」——去重闸=新旧标错判别器〔后续轮重判旧封印被闸挡回零触发〕;双条件②「结算时封印仍在
|
||||
# 场」由发射面既有过滤承载〔被挖开的封印已随挖掘擦除零兑付〕;grant_ap mode:queue 下一轮
|
||||
@@ -391,11 +391,11 @@ func _judge_seal_miss(evt: Dictionary, ri: int) -> void:
|
||||
elif String(h.get("kind", "")) == "forgive_seal_miss":
|
||||
# 完美保险(订阅式豁免:本战首次标错计一次豁免,只累加自有账
|
||||
# _perfect_forgiven,绝不回写 _perfect_hit_false=契约 2 计数纯净;发射时机与消费点零改动=契约 3)
|
||||
oc._perfect_forgiven += 1
|
||||
oc._facts.mark_perfect_forgiven()
|
||||
_apply_counter_hit(h) # 豁免同时记账(insurance_used battle 域——下次标错 when lt 1 不再命中)
|
||||
oc._emit_row({"type": "extended", "source_class": "seal_miss", "origin_cell": cell}, ri, "完美保险·标错豁免", 0,
|
||||
{"effect_id": "insurance_used", "forgiven": oc._perfect_forgiven})
|
||||
var hl := "perfect_broken" if oc._perfect_hit_false - oc._perfect_forgiven == 1 else ""
|
||||
{"effect_id": "insurance_used", "forgiven": oc._facts.perfect_forgiven})
|
||||
var hl := "perfect_broken" if oc._facts.perfect_hit_false - oc._facts.perfect_forgiven == 1 else ""
|
||||
oc._emit_row({"type": "seal_miss", "source_class": "seal_miss", "origin_cell": cell, "highlight": hl}, ri, "封印未中", 0, {})
|
||||
var snap = oc._reward_economy.grant(cell)
|
||||
if not (snap is Dictionary):
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
## 轮循环驱动件:每轮结算周期的唯一驱动——结算重入门闸(settling)、五段段序执行
|
||||
## (段序骨架冻结于 SettlementTable.segment_order)、开轮摇号(共识点 B:技能选择前置到轮次开始,
|
||||
## 摇定即本拍结算的选技)、踩雷计数账(转存时点=摇号轮末)。
|
||||
## 单一变化原因:轮结算周期的推进结构(段序、重入闸、摇号时序)。
|
||||
## 耦合边界:oc=宿主引用(五段段类既定同款直调形态)——经 oc 取 facts/协作件/行发射/出口分发;
|
||||
## 五段构造参数与持有形态不变(grant/combat 三引用、aura/decay/verdict 单引用);判定段零改动
|
||||
## (_exit_distribution 留宿主);随机只经 oc.rng 的 behavior_roll 封闭流(流名、开流时点、取号序逐字);
|
||||
## 零信号连接、零 await;随编排器每战新建同灭。
|
||||
class_name RoundCycle
|
||||
extends RefCounted
|
||||
|
||||
var oc: BattleOrchestrator # 宿主引用(段类同款直调——facts/协作件/行发射/出口分发取数单点)
|
||||
var mines_hits: Dictionary[Variant, Variant] = {"total": 0, "last": 0, "round": 0} # 踩雷计数(本场累计/上轮转存/当轮累计三读数合一账)
|
||||
var _grant_seg = null # GrantSegment(①授予段——含封印判与 counter/grant 助手单点)
|
||||
var _aura_seg = null # AuraSegment(②增益/减益段)
|
||||
var _combat_seg = null # CombatSegment(③战斗段)
|
||||
var _decay_seg = null # DecaySegment(④衰减段)
|
||||
var _verdict_seg = null # VerdictSegment(⑤判定段——返回裁定,终局早退语义归宿主)
|
||||
var _settling := false
|
||||
|
||||
|
||||
func _init(host: BattleOrchestrator, fx_host_ref: BattleFxHost, reward_grant_ref: RewardGrant) -> void:
|
||||
oc = host
|
||||
# 结算五段接线(授予/战斗两段持三引用=宿主+两协作件;信号连接纪律不涉段〔段零信号连接〕——五行自宿主 _init 逐字迁入)
|
||||
_grant_seg = GrantSegment.new(oc, fx_host_ref, reward_grant_ref)
|
||||
_aura_seg = AuraSegment.new(oc)
|
||||
_combat_seg = CombatSegment.new(oc, fx_host_ref, reward_grant_ref)
|
||||
_decay_seg = DecaySegment.new(oc)
|
||||
_verdict_seg = VerdictSegment.new(oc)
|
||||
|
||||
|
||||
# 结算重入门闸+段序体(原宿主 _maybe_settle 三闸与 _settle 合体——闸序 settling→battle_result→phase
|
||||
# 逐字;终局早退不回置 _settling,_battle_over 接管)
|
||||
func settle_if_due() -> void:
|
||||
if _settling or oc.battle_result != "":
|
||||
return
|
||||
if oc.action_economy.phase != oc.action_economy.PHASE_WAITING:
|
||||
return
|
||||
_settling = true
|
||||
var ri := oc.round_index
|
||||
# 段序编排(五段——段体归 game/core/settlement/,宿主只做行发射/开单原语单点)
|
||||
_grant_seg.run(ri) # ① 授予段(案C 闸随段装载)
|
||||
_aura_seg.run(ri) # ② 增益/减益段(续存实例组合行)
|
||||
_combat_seg.run(ri) # ③ 战斗段(主角先手 → 逐敌还手 → 地图伤害账殿后〔案C〕)
|
||||
_decay_seg.run(ri) # ④ 衰减段(恰一次恒执行含末轮——先兑付后衰减)
|
||||
var verdict: String = _verdict_seg.run(ri) # ⑤ 判定段(防御性优先级 hero 先判)
|
||||
if verdict != "continue":
|
||||
return # 终局:_settling 不回置——_battle_over 已接管
|
||||
_settling = false
|
||||
|
||||
|
||||
func is_settling() -> bool:
|
||||
return _settling
|
||||
|
||||
|
||||
# ---- 开轮摇号(共识点 B:技能选择前置到轮次开始,数值计算留结算段——原宿主函数逐字迁入)----
|
||||
# 每实例:保底判定(连续执行普攻 ≥ M → 必出特殊技、特殊技内按权重、不受冷却限制)→ 排除冷却中技能
|
||||
# (中签率 = 权重 ÷ 可摇权重合计——份额归一)→ 按行序逐敌从统一流顺序取号摇定本拍动作。
|
||||
# 随机消费只在换算层(本方法 + SkillLottery);单位容器收确定值(零随机纪律——armor_roll 先例同构)。
|
||||
# 统一流:behavior_roll 无子流派生向量(位置交错,单点定位由事件日志承载)。
|
||||
# 摇定后、兑现前死亡 → 本拍技能作废。
|
||||
func roll_round_actions() -> void:
|
||||
var pity_m: int = int(oc.db.combat.skill.pity_threshold)
|
||||
# facts 组包(开轮摇号前一次成型——last_round_end 空字典首轮映射 none 唯一落点;hero 事实不进 facts,
|
||||
# 容器内直读主角行)
|
||||
var facts := {
|
||||
"round_index": oc.round_index,
|
||||
"last_round_end": "none" if oc.action_economy.last_round_end().is_empty() else String(oc.action_economy.last_round_end().get("path_tag", "none")),
|
||||
"mines_hit_last": int(mines_hits["last"]),
|
||||
"mines_hit_total": int(mines_hits["total"]),
|
||||
}
|
||||
for u in oc._enemy_system.query_alive("enemy"):
|
||||
# Boss 半血解锁闩(迭代14④ T4——开轮摇号前逐敌检查;一次过门单向闩;解锁出一次归因明细行
|
||||
# 「XX 解锁了 YY」带 skill_unlock 高光键〔type=highlight 既有行型零新增〕,呈现层弹一次性
|
||||
# 技能名提示〔轻量 toast 非演出——D8 呈现面〕。门=确定性谓词,机制面零随机,摇号随机
|
||||
# 消费仍在 behavior_roll 既有流——同种子逐位复现不破坏)
|
||||
for sid in oc._enemy_system.check_trigger_unlocks(u, facts):
|
||||
var srow_u: Dictionary[Variant, Variant] = oc.db.combat.skill.row_by_id(sid)
|
||||
oc._emit_row({"type": "highlight", "source_class": "enemy_action", "origin_cell": Vector2i(-1, -1), "highlight": "skill_unlock"},
|
||||
oc.round_index, "%s 解锁了 %s" % [String(u.display_name), String(srow_u.get("display_name", sid))],
|
||||
0, {"skill_id": sid})
|
||||
# enemy_hp_threshold 发射点(内容数据驱动扩展批 T1——血量阈值沿;对所有带该字段敌人逐个发射,
|
||||
# 非 Boss 专属——Boss 语义留给订阅者 when 判定。pct=本次解锁条目的 trigger 行值)
|
||||
var pct_v := 0
|
||||
for pe in (u.get("pool", []) as Array):
|
||||
var pe_d: Dictionary[Variant, Variant] = pe
|
||||
if String(pe_d.get("skill_id", "")) == sid and (pe_d.get("trigger", {}) as Dictionary).has("value"):
|
||||
pct_v = int((pe_d.get("trigger", {}) as Dictionary).get("value", 0))
|
||||
break
|
||||
# target_attack_bonus 施加面(处刑台:敌血量阈值沿挂单位字典标记,
|
||||
# 主角攻击面 _resolve_hero_attack 通用消费——fx_atk_bonus 键加算进 base_value)
|
||||
var eht_hits := oc._fx_host.fx_emit("enemy_hp_threshold", {"unit": String(u.enemy_id), "pct": pct_v,
|
||||
"is_boss": String(oc._facts.encounter.get("node_type", "")) == "boss"})
|
||||
for h in eht_hits:
|
||||
if String(h.get("kind", "")) == "target_attack_bonus":
|
||||
u["fx_atk_bonus"] = int(u.get("fx_atk_bonus", 0)) + int(h.get("value", 0))
|
||||
var entries: Array[Variant] = oc._enemy_system.rollable_skills(u, facts)
|
||||
if oc._enemy_system.basic_streak(u) >= pity_m:
|
||||
var specials: Array[Variant] = oc._enemy_system.special_skills(u, facts)
|
||||
if not specials.is_empty():
|
||||
entries = specials # 保底命中——普攻恒可摇 → 非保底路径池恒非空,此为唯一替代集合
|
||||
var stream: RandomNumberGenerator = oc.rng.open_stream("behavior_roll")
|
||||
oc._enemy_system.set_pending_action(u, SkillLottery.draw(entries, stream))
|
||||
oc._enemy_system.tick_cooldowns() # 递减在摇号读值之后——"施放后连续 N 拍不可摇中"的等价实现(单位容器 注记)
|
||||
mines_hits["last"] = mines_hits["round"] # 轮次真正结束转存(轮内部分结算不更新)
|
||||
mines_hits["round"] = 0
|
||||
@@ -0,0 +1 @@
|
||||
uid://ce07smbypdcyj
|
||||
Reference in new issue
Block a user