diff --git a/game/core/battle_orchestrator.gd b/game/core/battle_orchestrator.gd index 694d9389..40397381 100644 --- a/game/core/battle_orchestrator.gd +++ b/game/core/battle_orchestrator.gd @@ -687,6 +687,17 @@ func _grant_routed(snap: Dictionary, polarity: String, source_class: String, cel return false if polarity == "positive": row["power"] = int(snap.get("power", int(row.power))) # 区间行快照 power(身份批 roll 值)覆盖表值——授予期零随机口径(E14) + # 标中兑付溢价(迭代14②判式换代批 T4——条款3 条件二旗溢价形态 a,2026-10-04 用户裁 P3): + # δ 读 settlement.flag_hit_premium(percent 域 125=×1.25 provisional);100=无溢价直通零扰动。 + # 兑付公式一处=本块:只乘标中旗正向(flat power 乘后入单据/治疗/排队;percent 幅度经 + # premium_pct 贯穿 _apply_percent_row 应用与呈现同乘)——标空/挖格/清图不乘,雷安同池冻结不动。 + # 取整=四舍五入(与伤害管线 round_direction=floor 分域——registry clause3_inequality 随批登记; + # 1 点量纲行 ac_up/action 取整后不变=整数粒度地板)。 + if source_class == "flag_hit" and int(db.settlement.flag_hit_premium) != 100: + var prem_pct: int = int(db.settlement.flag_hit_premium) + row = row.duplicate() + row["power"] = int(round(int(row.power) * prem_pct / 100.0)) + row["premium_pct"] = prem_pct # 惊巢反制(迭代 11 同调批 T5——底稿 §3:挖开雷格该次惩罚减半 + 反弹 N;duplicate 隔离——减半 # 不回写极性字典;仅 source_class=mine_hit 受理,标错旗/负向字典行走原通道) if polarity == "negative" and source_class == "mine_hit" and _attune_has("nest_counter"): @@ -717,10 +728,18 @@ func _apply_percent_row(row: Dictionary, source_class: String, cell: Vector2i, r var eff := String(row.effect_id) if eff == "gp_gain" or eff == "gp_loss": return _apply_gp_row(row, source_class, cell, ri, highlight, label_suffix) - var ok: bool = _status_effects.apply_effect(eff, {"source_class": source_class, "origin_cell": cell, "round_index": ri}) + var srow: Dictionary = db.status_effect_row(eff) + # 旗溢价贯穿(迭代14② T4——仅标中旗正向行携带 premium_pct;其余授予路径缺省 100 零扰动): + # 应用幅度与呈现行值同乘,容器经 magnitude_override 拿同一快照(抗表重载口径保持)。 + var prem_pct: int = int(row.get("premium_pct", 100)) + var eff_mag: int = int(srow.magnitude) + var src := {"source_class": source_class, "origin_cell": cell, "round_index": ri} + if prem_pct != 100: + eff_mag = int(round(eff_mag * prem_pct / 100.0)) + src["magnitude_override"] = eff_mag + var ok: bool = _status_effects.apply_effect(eff, src) if ok: - var srow: Dictionary = db.status_effect_row(eff) - _emit_row("effect", source_class, cell, ri, String(srow.display_name) + label_suffix, int(srow.magnitude), {"effect_id": eff, "pool_value": _pool_effective(eff)}, highlight) + _emit_row("effect", source_class, cell, ri, String(srow.display_name) + label_suffix, eff_mag, {"effect_id": eff, "pool_value": _pool_effective(eff)}, highlight) return true _emit_row("reward_ineffective", source_class, cell, ri, "奖励未生效(满层)%s" % label_suffix, 0, {"batch_key": eff}, highlight) return false diff --git a/game/core/status_container.gd b/game/core/status_container.gd index 30397dc0..63d8732e 100644 --- a/game/core/status_container.gd +++ b/game/core/status_container.gd @@ -42,6 +42,8 @@ func apply_effect(effect_id: String, source: Dictionary, duration_override: int var max_stack: int = int(row.max_stack) # 授予时快照(抗表重载——EC9) var snap_m: int = int(row.magnitude) + if source.has("magnitude_override"): + snap_m = int(source["magnitude_override"]) # 旗溢价贯穿(迭代14② T4——标中旗 percent 形态同乘快照;缺省路径零扰动) var snap_unit: String = String(row.unit) var snap_display: String = String(row.display_name) match policy: diff --git a/game/data/schemas/settlement_table.gd b/game/data/schemas/settlement_table.gd index aa02e936..6c8d60c3 100644 --- a/game/data/schemas/settlement_table.gd +++ b/game/data/schemas/settlement_table.gd @@ -8,6 +8,7 @@ extends Resource @export var equivalence_ref_damage: int = 12 # [1,999] knob——当量参考敞口 D_ref @export var p_perfect: int = 200 # {100,200} percent——完美排雷第二份兑付触发(载体域) +@export var flag_hit_premium: int = 100 # [100,999] percent knob——标中旗兑付溢价 ×(1+(n−100)/100):125=×1.25(条款3 条件二旗溢价形态 a,2026-10-05 判式换代批 provisional);100=无溢价直通零扰动。只乘标中旗正向兑付(flat power/percent 幅度/gp 缓冲三形态),标空/挖格/清图不乘;雷安同池冻结不动 @export var segment_order: PackedStringArray = [] # 结构冻结——恒等拍板段序校验违例致命 @export var source_label_map: Dictionary[String, Variant] = {} # 结构冻结——source_class→文案键 @export var effect_pool_map: Dictionary[String, Variant] = {} # 结构冻结——effect_id→pool(悬空加载致命) @@ -48,6 +49,8 @@ func validate() -> Array: errs.append({"category": "domain", "message": "equivalence_ref_damage 越域 [1,999]: %d" % equivalence_ref_damage}) if not P_PERFECT_DOMAIN.has(p_perfect): errs.append({"category": "pperfect_oob", "message": "p_perfect 载体域 {100,200}: %d" % p_perfect}) + if flag_hit_premium < 100 or flag_hit_premium > 999: + errs.append({"category": "domain", "message": "flag_hit_premium 越域 [100,999](100=无溢价): %d" % flag_hit_premium}) var seg := Array(segment_order) if seg != FROZEN_SEGMENT_ORDER: errs.append({"category": "segorder_violation", "message": "segment_order 违例——恒等拍板段序校验失败: %s" % str(seg)}) diff --git a/game/data/tables/settlement.tres b/game/data/tables/settlement.tres index 2c793289..14d39587 100644 --- a/game/data/tables/settlement.tres +++ b/game/data/tables/settlement.tres @@ -6,6 +6,7 @@ script = ExtResource("1") equivalence_ref_damage = 4 p_perfect = 200 +flag_hit_premium = 125 segment_order = PackedStringArray("grant", "buff_debuff", "combat", "decay", "verdict") source_label_map = { "safe_cell": "安全格", diff --git a/game/smoke/smoke_all.gd b/game/smoke/smoke_all.gd index eaed7315..503a245c 100644 --- a/game/smoke/smoke_all.gd +++ b/game/smoke/smoke_all.gd @@ -2420,6 +2420,46 @@ func _smoke_polarity_routing() -> void: if eff != "" and not POSITIVE_EFFECTS.has(eff): hit_ok = false check(hit_ok, "标中旗 → 该雷格资源的正向兑付行(origin 指回雷格,效果 ∈ 正向字典)") + # 条款3 条件二旗溢价断言(迭代14② T4——标中兑付行数值 = 同型正向 ×(1+δ)): + # δ 读 settlement.flag_hit_premium(125 provisional);九型正向行值全固定(唯一区间行 clear_blast + # 系清图槽不入格池)⇒ 逐型期望全确定。整数量级四舍五入域注记:ac_up/action 1 点量纲取整后不变 + # =整数粒度地板——等号压线判读在当量聚合面(audit 工具/registry clause3_inequality),非断言面。 + var prem_pct: int = int(_db.settlement.flag_hit_premium) + check(prem_pct == 125, "旗溢价配置在位(flag_hit_premium=125 provisional——形态 a 兑付溢价)") + var prem_rows := 0 + var prem_ok := true + for r in probe["rows"]: + if String(r.get("source_class", "")) != "flag_hit" or String(r.get("highlight", "")) != "flag_hit": + continue + prem_rows += 1 + var rtype := String(r.get("type", "")) + var v := int(r.get("value", 0)) + var eff := String(r.get("effect_id", "")) + if rtype == "effect": + if eff == "gp_gain": + prem_ok = prem_ok and v == int(round(3 * prem_pct / 100.0)) # 金币袋 3→4 + elif eff == "ap_delta": + prem_ok = prem_ok and v == 1 # +1AP:1 点量纲(round(1.25)=1——整数粒度地板) + else: + var mag: int = int(_db.status_effect_row(eff).get("magnitude", -999)) + prem_ok = prem_ok and v == int(round(mag * prem_pct / 100.0)) # 增伤50→63/削弱65→81/护甲1→1 + elif rtype == "heal": + # 急救 2→3(clamp 封顶只降不升:满血走 reward_ineffective 不入本行——区间断言) + prem_ok = prem_ok and v >= 1 and v <= int(round(2 * prem_pct / 100.0)) + elif rtype == "damage": + var at := String(r.get("attack_type", "")) + if at == "": + prem_ok = prem_ok and v == int(round(1 * prem_pct / 100.0)) # 爆裂粉尘 1→1(群伤行值=表值直付) + else: + # 穿刺/魔法 2→3(行值=落地伤=基准+克制点数——反推基准核对;damage_floor 兜底下成立) + prem_ok = prem_ok and (v - int(r.get("effectiveness", 0))) == int(round(2 * prem_pct / 100.0)) + check(prem_rows >= 1 and prem_ok, "标中兑付溢价(×%d 行逐型=同型正向 ×%d/100——等号压线注记:δ=1.25 时条件二 E[标中]=1.25·E_dig 恰等成立)" % [prem_rows, prem_pct]) + # 标空不乘溢价:负向直伤行(反噬6/陷阱8/魔法反噬8 固定表值)零溢价污染——溢价值挂标中正向单点 + var miss_flat_ok := true + for r in _rows_at(probe["rows"], "flag_miss", probe["miss_cell"]): + if String(r.get("type", "")) == "damage": + miss_flat_ok = miss_flat_ok and int(r.get("value", 0)) in [6, 8] + check(miss_flat_ok, "标空惩罚零溢价(负向直伤行=固定表值原值——溢价只挂标中正向)") # 标空旗:归因行 + 该安全格负向兑付行(flag_miss 来源) var miss_rows := _rows_at(probe["rows"], "flag_miss", probe["miss_cell"]) var miss_neg_ok := false @@ -3223,7 +3263,7 @@ func _smoke_level_graph() -> void: # 逐种子全关卡通关扫描找命中,期望路径过期时 258 次模拟撞 180s 闸(台账 257 + 2026-10-02 # 出度≤2 重建两次实证)。存储种子常态一次跑完;图表/数值有意变更致本断言红=快速失败(一次 # 即红非扫描超时),重采=临时脚本跑同款 run_level 循环取首命中种子回填(离线一次性)。 - const MAX_PATH_SEED := 42 + const MAX_PATH_SEED := 43 # 2026-10-05 判式换代批重采(旗溢价 δ=1.25 落地致种子 42 战局位移=败于终点;同款循环首命中——断言注释既定程序,临时脚本用后即删) var win_max: Dictionary = autoplay.run_level(_db, MAX_PATH_SEED, 2, 200, 100, false, null, "normal", "max", 0) check(win_max.result == "victory" and win_max.visited_ids == [0, 2, 6, 7, 8, 9], "L2·满配 max 路径(max 取最大编号候选)通关 = 0→2(奖励)→6→7→8(商店零购离开)→9(存储种子 %d——T17 出度≤2 拍板模板 0 重建)" % MAX_PATH_SEED)