iter46-卡1:换图系双基座七件批: 七件实装+全局damage_taken统一+BattleRefreshFlow拆件+词表扩签+数据37行——代码域闸全绿
This commit is contained in:
1 parent
b5b2c55557
commit
3fa99583fb
15 files changed
+1055
-76
No files matched your search
+29
-12
@@ -93,11 +93,29 @@ func request_dig(chain_size: int, clears_map: bool) -> bool:
|
||||
_reject("phase")
|
||||
return false
|
||||
var cost := _cost("dig")
|
||||
# dig_paid 发射+施加(付费开掘发起、动作经济闸收对价前:
|
||||
# dig_paid 发射+施加(付费开掘发起、动作经济闸收对价前——施加单点 _apply_dig_paid_hits):
|
||||
# counter_spend 命中=尝试加收对价并积计数;资源不足走 fallback/耗尽即止=只付常规基础对价。
|
||||
# counter_add〔双管镐 付费挖格计数〕/ grant_ap〔每第 2 次返 1 AP——对价减免,
|
||||
# mod_eq 闸在行 when〕同面施加)
|
||||
var apply_res := _apply_dig_paid_hits(cost)
|
||||
cost = int(apply_res["cost"])
|
||||
if _ap < cost:
|
||||
_reject("resource_face")
|
||||
return false # 拒绝轮零入池(矿脉储能只在扣费受理后兑付——C2 成功才登记同款纪律)
|
||||
if int(apply_res["refund"]) > 0:
|
||||
cost = maxi(0, cost - int(apply_res["refund"])) # 返还=对价减免(净费不低于 0——免费开格不产生负对价)
|
||||
var accepted := _spend_cost_and_arbitrate(cost, clears_map)
|
||||
if accepted and int(apply_res["rap_gain"]) > 0:
|
||||
grant_reserve_ap(int(apply_res["rap_gain"])) # 每次受理的付费挖格产 RAP(一次性入池——每动作恰一挖,连锁不二次)
|
||||
return accepted
|
||||
|
||||
|
||||
# dig_paid 命中施加单点(迭代 46 卡A T3 自 request_dig 迁出——分支本体逐字保留:
|
||||
# counter_spend 加收对价并积计数/counter_add 施加〔双管镐 付费挖格计数〕/
|
||||
# grant_ap 对价减免〔每第 2 次返 1 AP——mod_eq 闸在行 when〕/grant_reserve_ap 矿脉储能累计;
|
||||
# 命中序=声明序不变。返回 {cost, refund, rap_gain} 交受理面消费)
|
||||
func _apply_dig_paid_hits(base_cost: int) -> Dictionary:
|
||||
var cost := base_cost
|
||||
var dig_refund := 0
|
||||
var rap_gain := 0
|
||||
if _fx != null:
|
||||
for h in _fx.dispatch(_ctx, "dig_paid", {"ap_cost": cost, "ap_surplus": _ap - cost}):
|
||||
if String(h.get("kind", "")) == "counter_spend":
|
||||
@@ -110,12 +128,9 @@ func request_dig(chain_size: int, clears_map: bool) -> bool:
|
||||
EffectEngine.counter_add(_ctx, String(h.get("counter_id", "")), int(h.get("value", 0)) if set_v == null else int(set_v), set_v != null)
|
||||
elif String(h.get("kind", "")) == "grant_ap":
|
||||
dig_refund += int(h.get("value", 0))
|
||||
if _ap < cost:
|
||||
_reject("resource_face")
|
||||
return false
|
||||
if dig_refund > 0:
|
||||
cost = maxi(0, cost - dig_refund) # 返还=对价减免(净费不低于 0——免费开格不产生负对价)
|
||||
return _spend_cost_and_arbitrate(cost, clears_map)
|
||||
elif String(h.get("kind", "")) == "grant_reserve_ap":
|
||||
rap_gain += int(h.get("value", 0))
|
||||
return {"cost": cost, "refund": dig_refund, "rap_gain": rap_gain}
|
||||
|
||||
|
||||
func _spend_cost_and_arbitrate(cost: int, clears_map: bool) -> bool:
|
||||
@@ -196,13 +211,15 @@ func finish_round_stop(transfer: bool, transfer_pct: int = 100) -> void:
|
||||
# 轮内刷新:唯一入口 =
|
||||
# Active 相位——仅扣 RAP,相位与 AP 均不动。刷新不打断轮次、不触发结算;换图编排归 战斗结算
|
||||
# (retire + install 立即执行,玩家同轮继续挖新图)。决策主体 = 玩家(经 HUD框架发起)纪律不变。
|
||||
func request_refresh() -> bool:
|
||||
# cost_override=折后价入参(迭代 46 卡A T3——BattleRefreshFlow 折价读数传入;缺省 -1=表基线逐位不变)
|
||||
func request_refresh(cost_override: int = -1) -> bool:
|
||||
if _phase != Phase.ACTIVE:
|
||||
_reject("phase")
|
||||
return false
|
||||
if _rap < db.run.action_economy.rap_refresh_cost:
|
||||
var cost := int(db.run.action_economy.rap_refresh_cost) if cost_override < 0 else cost_override
|
||||
if _rap < cost:
|
||||
return false # EC13 资源不足拒绝——合法相位内资源拒绝,非编排错误
|
||||
_rap -= db.run.action_economy.rap_refresh_cost
|
||||
_rap -= cost
|
||||
return true
|
||||
|
||||
|
||||
|
||||
@@ -31,8 +31,9 @@ signal settlement_snapshot(snap: Dictionary) ## 每结算末尾的全量状态
|
||||
const SOURCE_EXEMPT_TYPES := ["decay", "verdict"]
|
||||
# 行来源断言豁免集合(来源类别层)——事实来源是单位 / 清图而非棋盘格;
|
||||
# fx_reveal=专长揭示掷格(落空行无真实格);
|
||||
# fx_grant_gp=专长·GP 入账(钱包面而非棋盘面,行无格子可指)
|
||||
const SOURCE_EXEMPT_CLASSES := ["hero_attack", "enemy_action", "clear_reward", "fx_reveal", "fx_grant_gp"]
|
||||
# fx_grant_gp=专长·GP 入账(钱包面而非棋盘面,行无格子可指);
|
||||
# fx_board_refresh=成功刷新事实族(迭代 46 卡A——崩壁冲击群伤行源=换图动作而非棋盘格)
|
||||
const SOURCE_EXEMPT_CLASSES := ["hero_attack", "enemy_action", "clear_reward", "fx_reveal", "fx_grant_gp", "fx_board_refresh"]
|
||||
|
||||
var _facts: BattleFacts # 战斗事实件(battle_facts.gd——事实族 15 成员单点)
|
||||
var _rounds: RoundCycle # 轮循环驱动件(settlement/round_cycle.gd——五段持有/段序/重入闸/摇号)
|
||||
@@ -596,26 +597,17 @@ func _exit_distribution() -> void:
|
||||
round_started.emit(round_index)
|
||||
|
||||
|
||||
# 呈现层查询面(HUD 刷新按钮可用性)——挖掘期唯一通道
|
||||
# 呈现层查询面(HUD 刷新按钮可用性)——挖掘期唯一通道(折价成本同源:判据归 BattleRefreshFlow)
|
||||
func can_refresh() -> bool:
|
||||
return battle_result == "" \
|
||||
and _facts.refresh_used < int(db.run.action_economy.refresh_cap_per_round) \
|
||||
and action_economy.phase == action_economy.PHASE_ACTIVE \
|
||||
and action_economy.rap >= int(db.run.action_economy.rap_refresh_cost)
|
||||
return BattleRefreshFlow.can_refresh(self)
|
||||
|
||||
|
||||
# 玩家经 HUD框架发起、战斗结算 代理调用(禁止 RAP 满自动刷)。
|
||||
# 挖掘期唯一通道:Active 相位立即换图
|
||||
# 继续挖(RAP -8;AP 保留、相位不动、不触发结算);非挖掘期请求一律拒绝——非清图轮恒同图。
|
||||
# 挖掘期唯一通道:Active 相位立即换图继续挖(RAP 按折后价扣;AP 保留、相位不动、不触发结算);
|
||||
# 非挖掘期请求一律拒绝——非清图轮恒同图。刷新门/折价扣费/换图/成功事实归 BattleRefreshFlow
|
||||
# (迭代 46 卡A T3 拆出——编排器入口与唯一通道不变,C10 结构预算只降不升)。
|
||||
func player_request_refresh() -> bool:
|
||||
if not can_refresh():
|
||||
return false
|
||||
if not action_economy.request_refresh():
|
||||
return false
|
||||
_facts.refresh_used += 1
|
||||
_reward_economy.retire_mapping() # 旧图批次退役(地图战斗资源 Ready→retired;E6 新批重置前提)
|
||||
minesweeper.retire_board(true) # 旧板退役(轮内通道)
|
||||
return _install_and_reset(true) # 当场换图——失败即编排违例 fail-fast
|
||||
return BattleRefreshFlow.execute(self)
|
||||
|
||||
|
||||
func _battle_over(result: String) -> void:
|
||||
|
||||
@@ -460,8 +460,8 @@ func _hero_attack_deliver(t: Dictionary, ctx: Dictionary, redemption: Dictionary
|
||||
# 敌方伤害技:掷点 → 折扣/暴击 → 克制点数(attack_type vs 主角护甲类型——
|
||||
# 无类型恒中性 delta 0,写法同 hero_attack 的 _counter_delta 消费位)→ hero_defense×enemy_output
|
||||
# 池乘区 → 下限 → +rider(后置必中附加)→ 交付 → commit_action(作废单不 commit——死亡即不动手)。
|
||||
# 掷点算术归 _enemy_roll;damage_taken 施加面归 _enemy_shield_apply(发射在本函数——
|
||||
# 与减伤落快照的先后序固定)。
|
||||
# 掷点算术归 _enemy_roll;damage_taken 统一发射+消费归 _emit_hero_damage_taken(发射在本函数——
|
||||
# 与减伤落快照的先后序固定;「掷点后、交付前」消费时点不变)。
|
||||
func _resolve_enemy_skill(t: Dictionary) -> void:
|
||||
var hero: Dictionary[Variant, Variant] = units.hero_unit()
|
||||
var roll := _enemy_roll(t)
|
||||
@@ -469,9 +469,8 @@ func _resolve_enemy_skill(t: Dictionary) -> void:
|
||||
# damage_taken 发射(kind=enemy_skill;铁壁整备减伤订阅面:shield 加法族合计 value×per(charge_layers),
|
||||
# 稳健拓荒树规则同面(rebuild 合成订阅);减后过下限保底。damage_reduce〔背水 hp_ratio when〕/
|
||||
# counter_add〔保险丝/石肤〕/ac_bonus〔石肤〕同面施加;hp_ratio fact 由 _fx_fact 补充事实面回落提供)
|
||||
var dt_hits := _fx_hits("damage_taken", {"kind": "enemy_skill", "amount": total,
|
||||
"source": String(t.context.get("skill_id", "")), "round": int(t.round_index)})
|
||||
total = int(_enemy_shield_apply(dt_hits, total)["total"])
|
||||
var dt_res := _emit_hero_damage_taken(total, "enemy_skill", String(t.context.get("skill_id", "")), t.origin_cell, int(t.round_index))
|
||||
total = int(dt_res["total"])
|
||||
units.apply_damage(hero, total)
|
||||
var payload: Dictionary[Variant, Variant] = {"target": "hero", "skill_id": String(t.context.get("skill_id", "")), "baseline": int(t.context.get("baseline", 0)),
|
||||
"roll": int(roll["roll"]), "ac": int(roll["threshold"]), "tier": int(roll["discount"]), "attack_type": String(t.attack_type)}
|
||||
@@ -502,9 +501,22 @@ func _enemy_roll(t: Dictionary) -> Dictionary:
|
||||
return {"roll": int(roll_read.roll), "threshold": threshold, "crit": crit, "discount": discount, "total": total}
|
||||
|
||||
|
||||
# damage_taken 施加面(shield 加法族合计;damage_reduce 逐条减量〔背水〕;ac_bonus 转编排器单点
|
||||
# 〔石肤 AC 累积归 set_hero_ac_override 消费面〕;counter_add 施加)。返回 {total, shield}。
|
||||
func _enemy_shield_apply(hits: Array, total: int) -> Dictionary:
|
||||
# 全局受伤发射单点(迭代 46 卡A T2——所有主角承伤路径唯一发射口:敌方攻击/地形/危险格/错误封印
|
||||
# 资源直伤(后三者经 board_flat_hero 单据进入)都经此 dispatch 一次 damage_taken 并消费一次;
|
||||
# 同一伤害单据重复发射由 context.hero_damage_consumed 标记闸拦(地形路径在开单点标记)。
|
||||
# payload 必含 kind/amount/source/cell/round/hp_ratio;返回 {total, hits} 交调用侧按减后值开单/交付)。
|
||||
func _emit_hero_damage_taken(amount: int, damage_kind: String, source: String, cell: Vector2i, ri: int) -> Dictionary:
|
||||
var hu: Dictionary[Variant, Variant] = units.hero_unit()
|
||||
var payload: Dictionary[Variant, Variant] = {"kind": damage_kind, "amount": amount, "source": source,
|
||||
"cell": cell, "round": ri, "hp_ratio": int(round(100.0 * float(int(hu.get("hp", 0))) / float(maxi(1, int(hu.get("max_hp", 1))))))}
|
||||
var hits := _fx_hits("damage_taken", payload)
|
||||
return {"total": int(_apply_hero_damage_effects(hits, amount)["total"]), "hits": hits}
|
||||
|
||||
|
||||
# damage_taken 唯一消费族(组合次序冻结:shield 加法族合计→damage_reduce 逐条减量〔背水/石层缓冲〕→
|
||||
# ac_bonus 转编排器单点〔石肤 AC 累积归 set_hero_ac_override 消费面〕→counter_add 施加〔保险丝/石肤/
|
||||
# 换图系临时计数夹具〕。返回 {total, shield})。
|
||||
func _apply_hero_damage_effects(hits: Array, total: int) -> Dictionary:
|
||||
var shield := 0
|
||||
for h in hits:
|
||||
match String(h.get("kind", "")):
|
||||
@@ -565,9 +577,15 @@ func _resolve_board_blast(t: Dictionary) -> void:
|
||||
_outcomes[int(t.ticket_id)] = "redeemed"
|
||||
|
||||
|
||||
# 棋盘主角直伤(反噬/治疗包负向/地形变异):无类型必中,下限保底;context 键并入行载荷
|
||||
# 棋盘主角直伤(反噬/治疗包负向/危险格/错误封印资源直伤):无类型必中,下限保底;context 键并入行载荷。
|
||||
# damage_taken 全局发射点(迭代 46 卡A T2——单据未标 hero_damage_consumed 时在下限前发射并消费一次;
|
||||
# 地形路径已在授予段开单点发射并标记,此处跳过防重复)
|
||||
func _resolve_board_flat_hero(t: Dictionary) -> void:
|
||||
var dealt: int = maxi(int(db.combat.settlement.damage_roll.damage_floor), int(t.base_value)) # 伤害下限全来源
|
||||
var dealt: int = int(t.base_value)
|
||||
if not bool((t.get("context", {}) as Dictionary).get("hero_damage_consumed", false)):
|
||||
var res_flat := _emit_hero_damage_taken(dealt, "board_flat_hero", String(t.get("source_class", "")), t.origin_cell, int(t.round_index))
|
||||
dealt = int(res_flat["total"])
|
||||
dealt = maxi(int(db.combat.settlement.damage_roll.damage_floor), dealt) # 伤害下限全来源(减后过下限)
|
||||
units.apply_damage(units.hero_unit(), dealt)
|
||||
var extra: Dictionary[Variant, Variant] = {"target": "hero"}
|
||||
for k in t.context.keys():
|
||||
|
||||
@@ -12,11 +12,15 @@ extends RefCounted
|
||||
const EVENTS := ["dig_reveal", "dig_paid", "seal_hit", "mine_hit", "attack_commit", "clamp_check",
|
||||
"armor_roll", "kill", "damage_taken", "enemy_hp_threshold", "round_start", "seal_settle",
|
||||
"round_end", "reward_roll", "treasure_used", "charge_full", "dig_stop", "battle_won", "seal_missed",
|
||||
"board_installed"]
|
||||
"board_installed",
|
||||
# 换图系双事件(refresh_request=玩家请求刷新〔省力周转 apply_discount 订阅面——折扣只改门槛
|
||||
# 与扣费不改拒绝判据〕;board_refreshed=成功刷新事实〔换图系七件订阅主挂点——装新板后才发射〕)
|
||||
"refresh_request", "board_refreshed"]
|
||||
|
||||
## 扫雷侧事件集(🔴 流派扫雷触发铁律新形态:每流派 ≥1 行订阅本集事件——schema 加载校验。
|
||||
## 原 MINE_HOOKS 的同义迁移:挖掘/封印/轮末结算面事件)
|
||||
const MINE_EVENTS := ["dig_reveal", "dig_paid", "seal_hit", "mine_hit", "seal_settle", "round_end", "reward_roll"]
|
||||
## 原 MINE_HOOKS 的同义迁移:挖掘/封印/轮末结算面事件+轮内刷新面〔换图系〕)
|
||||
const MINE_EVENTS := ["dig_reveal", "dig_paid", "seal_hit", "mine_hit", "seal_settle", "round_end", "reward_roll",
|
||||
"refresh_request", "board_refreshed"]
|
||||
|
||||
## 效果类型词汇(解释器 switch 闭集——词表实数以 EFFECT_KINDS 常量为准,含共享行拆型:
|
||||
## grant_gp/bias_wallet、counter_add/counter_spend、reveal_tiles/remove_mines/refresh_pick、
|
||||
@@ -40,7 +44,11 @@ const EFFECT_KINDS := ["add_ticket_rider", "modify_ticket", "damage_mult", "open
|
||||
"mine_count_preview",
|
||||
# forgive_seal_miss=完美保险(本场首次封印落空不计入完美
|
||||
# 封印判定——订阅 seal_missed 的豁免效果,消费点在授予段;feats.tres 首例 domain=battle 行)
|
||||
"forgive_seal_miss"]
|
||||
"forgive_seal_miss",
|
||||
# 换图系两效果(grant_reserve_ap=矿脉储能·付费挖格产 RAP〔消费点在行动经济 dig_paid
|
||||
# 受理后一次性入池〕;apply_discount=省力周转·刷新成本折扣〔mode=refresh cost_mult 百分比,
|
||||
# floor 取整——只改门槛与扣费、不改拒绝判据〕)
|
||||
"grant_reserve_ap", "apply_discount"]
|
||||
|
||||
## fact 条件词汇(封闭枚举——payload 同名键直读面〔fact 取值序 payload
|
||||
## 优先——effect_engine._fact_value 既有机制〕。new_resource_type=首开资源类型〔地质学家〕;
|
||||
|
||||
@@ -365,6 +365,12 @@ func outcome_of(ticket_id: int) -> String:
|
||||
return "redeemed" if ticket_id < 0 else damage.outcome(ticket_id)
|
||||
|
||||
|
||||
# 延迟单据入队(迭代 46 卡A T4——成功刷新的崩壁冲击群伤单走案C 同队列:授予段闸外唯一入口,
|
||||
# 战斗段末 _board_deferred_settle 按开单序补提交统一结账;类变量零增员——复用 defer.queue)
|
||||
func defer_ticket(t: Dictionary) -> void:
|
||||
(defer.queue as Array).append(t)
|
||||
|
||||
|
||||
# 主角直伤单据(反噬/治疗包负向——无类型必中,下限保底在控制器管线内)
|
||||
func _submit_flat_hero(display: String, power: int, att: Dictionary, sync: bool) -> String:
|
||||
var t := damage.open_ticket(DamageController.KIND_BOARD_FLAT_HERO, String(att.get("source_class", "")), display,
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
class_name BattleRefreshFlow
|
||||
extends RefCounted
|
||||
## 换图刷新流程件(迭代 46 卡A T3/T4 自编排器拆出):刷新可用性门、折价扣费、换图执行与成功事实登记。
|
||||
## 拆分边界(需求卡片 C13):本件只负责可用性、扣费、换图与成功事实登记——七件效果的算法留在
|
||||
## 效果引擎、授予段与伤害控制器。调用路径=呈现层→编排器单行转发→本件→行动经济/装板壳/授予段。
|
||||
## 反自动刷新(C11):只经玩家入口发起,禁 RAP 满自动刷——编排器公开面单行转发,无自动调用点。
|
||||
## 成功序钉死(T4):折价扣 RAP→refresh_used+1→旧资源退役→旧板退役→装新板→授予段成功事实发射;
|
||||
## 装板失败返回 false 且零效果——成功事实只在新板就位后发射。
|
||||
|
||||
|
||||
## 折价成本读数(refresh_request 命中省力周转 apply_discount——只认 kind==apply_discount 且
|
||||
## mode==refresh,取声明序第一命中,floor(base×cost_mult/100);无命中=表基线逐位不变。
|
||||
## can_refresh 与 execute 同源取数〔V3——can 与执行同源判断〕;折扣只改变门槛与扣费,
|
||||
## 不改变拒绝判据〔C2——每轮上限与相位判据照旧〕)
|
||||
static func _effective_refresh_cost(oc: BattleOrchestrator) -> int:
|
||||
var base := int(oc.db.run.action_economy.rap_refresh_cost)
|
||||
for h in oc.fx_host().fx_emit("refresh_request", {"mode": "refresh", "base": base}):
|
||||
if String(h.get("kind", "")) == "apply_discount" and String(h.get("mode", "")) == "refresh":
|
||||
return int(floor(float(base) * float(int(h.get("cost_mult", 100))) / 100.0))
|
||||
return base
|
||||
|
||||
|
||||
## 可用性门(HUD 刷新按钮同源判据):战斗未终局、每轮上限未满、Active 相位、RAP 抵折后价。
|
||||
static func can_refresh(oc: BattleOrchestrator) -> bool:
|
||||
return oc.battle_result == "" \
|
||||
and oc._facts.refresh_used < int(oc.db.run.action_economy.refresh_cap_per_round) \
|
||||
and oc.action_economy.phase == oc.action_economy.PHASE_ACTIVE \
|
||||
and oc.action_economy.rap >= _effective_refresh_cost(oc)
|
||||
|
||||
|
||||
## 执行(玩家请求刷新唯一通道体):扣费受理后继续;扣费拒绝/门拒零效果零事实。
|
||||
static func execute(oc: BattleOrchestrator) -> bool:
|
||||
if not can_refresh(oc):
|
||||
return false
|
||||
if not oc.action_economy.request_refresh(_effective_refresh_cost(oc)):
|
||||
return false
|
||||
oc._facts.refresh_used += 1
|
||||
oc._reward_economy.retire_mapping() # 旧图批次退役(地图战斗资源 Ready→retired;E6 新批重置前提)
|
||||
oc.minesweeper.retire_board(true) # 旧板退役(轮内通道)
|
||||
if not oc._install_and_reset(true): # 当场换图——失败即编排违例 fail-fast(零成功事实)
|
||||
return false
|
||||
oc._rounds._grant_seg.apply_board_refreshed(oc.round_index) # 成功事实:新板就位后一次发射
|
||||
return true
|
||||
@@ -0,0 +1 @@
|
||||
uid://d2kjxlt5b2eqv
|
||||
@@ -6,7 +6,8 @@ extends RefCounted
|
||||
# 效果施加归 BattleFxHost(段持三引用直调,零转发壳)——
|
||||
# 本段只搬运时序,零算法改动(🔴 零行为变更契约:同种子完整局输出逐位一致)。
|
||||
# run 编排骨架+批私有族(_reveal_batch/_terrain_batch/_seal_batch/_round_end_apply,段内施加面
|
||||
# 再拆 _reveal_safe_apply/_reveal_mine_apply/_terrain_damage_reduce/_seal_hit_effects 等单面函数);
|
||||
# 再拆 _reveal_safe_apply/_reveal_mine_apply/_seal_hit_effects 等单面函数);地形 damage_taken
|
||||
# 消费随迭代 46 卡A T2 并入伤害控制器全局消费族(本段零本地减伤函数);
|
||||
# kind 分派单点化(P1-1 同批):counter_add 五位三行组 / grant_material 三位兑付块
|
||||
# 收 _apply_counter_hit / _apply_material_hit 两助手(分支本体逐字保留在助手内)。
|
||||
|
||||
@@ -32,6 +33,27 @@ func run(ri: int) -> void:
|
||||
_round_end_apply(ri)
|
||||
|
||||
|
||||
# 成功刷新事实发射+施加(迭代 46 卡A T4——BattleRefreshFlow 装新板后单点调用,每成功刷新恰一次;
|
||||
# 拒绝刷新零事实〔C2〕。命中消费三面:counter_add→既有单点落账〔蓄力周转/石层缓冲/坑道小憩 计数〕;
|
||||
# grant_gp→战斗内缓冲 escrow 入账+fx_grant_gp 行〔矿道红利——不绑清图奖励,C7〕;
|
||||
# open_ticket channel=blast→崩壁冲击群伤单延迟入队〔案C 同队列,战斗段末按存活目标结账〕)
|
||||
func apply_board_refreshed(ri: int) -> void:
|
||||
var br_hits := fx_host.fx_emit("board_refreshed", {"round": ri})
|
||||
for h in br_hits:
|
||||
if String(h.get("kind", "")) == "counter_add":
|
||||
_apply_counter_hit(h)
|
||||
for h in br_hits:
|
||||
if String(h.get("kind", "")) == "grant_gp":
|
||||
reward_grant.escrow += int(h.get("value", 0))
|
||||
oc._emit_row({"type": "effect", "source_class": "fx_grant_gp", "origin_cell": Vector2i(-1, -1)}, ri, "专长·GP 入账 +%d" % int(h.get("value", 0)), int(h.get("value", 0)), {"effect_id": "fx_grant_gp", "escrow": reward_grant.escrow})
|
||||
for h in br_hits:
|
||||
if String(h.get("kind", "")) == "open_ticket" and String(h.get("channel", "")) == "blast":
|
||||
var bb_t := oc._damage.open_ticket(DamageController.KIND_BOARD_BLAST, "fx_board_refresh", "崩壁冲击",
|
||||
{"channel": "board", "base_value": int(h.get("value", 0)), "target_rule": DamageController.TARGET_ALL_ALIVE,
|
||||
"ri": ri, "origin_cell": Vector2i(-1, -1)})
|
||||
reward_grant.defer_ticket(bb_t)
|
||||
|
||||
|
||||
# 开格/踩雷兑付批(轮 facts_reveals 资源事件序:safe 正向乘区兑付 / mine_hit 减半负向兑付)
|
||||
func _reveal_batch(ri: int) -> void:
|
||||
for evt in oc._facts.reveals:
|
||||
@@ -167,37 +189,22 @@ func _terrain_batch(ri: int) -> void:
|
||||
if String(vrow.get("effect", "")) != "flat_damage":
|
||||
continue # 触发词表按 effect 路由:flat_damage=on_open 兑现;hide_number/on_open 外组合 = 数据行新词表未接线(显式忽略面)
|
||||
# 地形变异伤害单据——无类型必中,下限保底在控制器管线内
|
||||
# damage_taken 发射在单据开立前:damage_reduce〔背水——hp_ratio when
|
||||
# 面〕先收集再按减后值开单;counter_add〔保险丝/石肤〕+ ac_bonus〔石肤〕照常施加;
|
||||
# grant_material〔荆棘/地脉〕移到单据提交后(兑付值序一致——收益不因减伤变化)
|
||||
# damage_taken 统一发射(迭代 46 卡A T2——地形路径并入全局消费族 _emit_hero_damage_taken:
|
||||
# 发射在单据开立前、减后值开单,组合消费含 shield〔全局受伤语义〕;
|
||||
# hero_damage_consumed 标记入单据 context——战斗段末 _resolve_board_flat_hero 跳过重复发射;
|
||||
# grant_material〔荆棘/地脉〕移到单据提交后(兑付值序一致——收益不因减伤变化))
|
||||
var dt_amount := int(vrow.get("effect_value", 0))
|
||||
var dt_hits := fx_host.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))))))})
|
||||
dt_amount = _terrain_damage_reduce(dt_hits, dt_amount)
|
||||
var dt_res := oc._damage._emit_hero_damage_taken(dt_amount, "terrain", String(vid), evt.cell, ri)
|
||||
dt_amount = int(dt_res["total"])
|
||||
var vt := oc._damage.open_ticket(DamageController.KIND_BOARD_FLAT_HERO, "地形变异", String(vrow.get("display_name", vid)),
|
||||
{"channel": "board", "base_value": dt_amount, "target_rule": DamageController.TARGET_HERO,
|
||||
"ri": ri, "origin_cell": evt.cell, "context": {"variant_id": String(vid)}})
|
||||
"ri": ri, "origin_cell": evt.cell, "context": {"variant_id": String(vid), "hero_damage_consumed": true}})
|
||||
reward_grant.submit(vt, false)
|
||||
for h in dt_hits:
|
||||
for h in (dt_res["hits"] as Array):
|
||||
if String(h.get("kind", "")) == "grant_material":
|
||||
_apply_material_hit(h, evt.cell, ri)
|
||||
|
||||
|
||||
# damage_taken 施加面(damage_reduce 减量收集〔背水——定值〕/ac_bonus〔石肤〕/counter_add〔保险丝/石肤〕;
|
||||
# 返回减后 amount 交开单消费)
|
||||
func _terrain_damage_reduce(dt_hits: Array, dt_amount: int) -> int:
|
||||
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":
|
||||
fx_host.apply_ac_bonus(h)
|
||||
"counter_add":
|
||||
_apply_counter_hit(h)
|
||||
return dt_amount
|
||||
|
||||
|
||||
# 封印判定批+战封印军规开单段(封印流:seal_judged 批后统一开单:轮末每面封印命中对最前存活敌
|
||||
# 结算 board_typed 必中伤害〔复用零新配方;「封印所在巢穴敌」简化为 default_target 最前存活敌——
|
||||
# 台账披露待追认〕;完美布防=本轮封印批全中(hit>0 且 miss==0)时封印伤 ×mult——全对推理奖励)。
|
||||
@@ -259,6 +266,7 @@ func _seal_strike_value(fs_fx: Array, fs_hits: int, fs_misses: int) -> Dictionar
|
||||
func _round_end_apply(ri: int) -> void:
|
||||
var re_fx := fx_host.fx_emit("round_end", {"round": ri})
|
||||
_round_end_blast_tickets(re_fx, ri)
|
||||
_round_end_heal_value_counter(re_fx, ri) # 迭代 46 卡A T5——坑道小憩恢复兑付(先于清零行消费层值,声明序=heal 行在 counter set 行前)
|
||||
for h in re_fx:
|
||||
if String(h.get("kind", "")) == "counter_add":
|
||||
_apply_counter_hit(h)
|
||||
@@ -278,6 +286,24 @@ func _round_end_apply(ri: int) -> void:
|
||||
oc._damage.flush() # 授予段界结账(案C 后本段伤害单据全数暂存,此处对空队 no-op——保留作防御性段界)
|
||||
|
||||
|
||||
# round_end heal value_counter 兑付(迭代 46 卡A T5——坑道小憩:层值=本轮成功刷新累计恢复点,
|
||||
# units.heal 封顶、满血发未生效行;层清零由同事件 counter_add set 行承载〔声明序在后〕——本面
|
||||
# 先于 counter_add 遍历消费层值即保序。行源=成功刷新事实族(无棋盘格——fx_board_refresh 豁免类))
|
||||
func _round_end_heal_value_counter(re_fx: Array, ri: int) -> void:
|
||||
for h in re_fx:
|
||||
if String(h.get("kind", "")) != "heal" or String(h.get("value_counter", "")) == "":
|
||||
continue
|
||||
var layers := EffectEngine.counter(fx_host.counters_ctx, String(h.get("value_counter", "")))
|
||||
if layers <= 0:
|
||||
continue
|
||||
var hu: Dictionary[Variant, Variant] = oc._enemy_system.hero_unit()
|
||||
if int(hu.get("hp", 0)) >= int(hu.get("max_hp", 1)):
|
||||
oc._emit_row({"type": "reward_ineffective", "source_class": "fx_board_refresh", "origin_cell": Vector2i(-1, -1)}, ri, "坑道小憩 未生效(满血)", 0, {"batch_key": String(h.get("value_counter", ""))})
|
||||
continue
|
||||
var healed: int = oc._enemy_system.heal(hu, layers)
|
||||
oc._emit_row({"type": "heal", "source_class": "fx_board_refresh", "origin_cell": Vector2i(-1, -1)}, ri, "坑道小憩 回复", healed, {"target": "hero"})
|
||||
|
||||
|
||||
# round_end blast 通道反打单(per-counter 积层读数×value=反打总量;source_class 用中性名,
|
||||
# per-counter 反打通道保留泛用面;案C 暂存战斗段末兑付)
|
||||
func _round_end_blast_tickets(re_fx: Array, ri: int) -> void:
|
||||
|
||||
Reference in new issue
Block a user