拆件批v1.3-B3伴随(私有助手抽取与用语统一): unit_container 抽 _pool_snapshot(开战实例池快照循环体逐字迁移)与 _pct_fact_blocked(self/hero 百分比事实阈值判定——分支逐字承原,六算子统一在阈值上)、skill_table validate 抽 _validate_trigger/_validate_trigger_domain/_validate_trigger_value/_validate_basic_row 四私有段(报错顺序=报告顺序逐字承原,行缺 trigger 早退等价)、config_db_cross_validator 抽 _pool_cast_side_errs 并修复拆分稿缺陷——append_array 误落逐行循环内会按技能行数重复追加守卫报错,移回全表恰一次恢复单份报错序;curio_deck/effect_context/level_autoplay 注释与 enemy.tres/status_effects.tres 调参登记注用语统一(通关→冒险成功/关卡完成率——零数值零行为改动)。验收:全量套件 63 绿+round_flow EV 锚 goblin 已知预期红 1;bp 对拍 292dumps×28 键 mismatch=0(双基线);冒烟 17 项 0 失败;gdstyle 基线外新违规 0/恶化恰 2(存量债)〔领域拆分批 V1〕
This commit is contained in:
1 parent
012883f301
commit
45faa92bc5
8 files changed
+115
-76
No files matched your search
@@ -118,12 +118,9 @@ func cross_validate(loaded: Dictionary, push_diag: Callable) -> void:
|
||||
# proposal-status-vocabulary §1.2)+ 施放类 side 守卫(增益引用 enemy 侧 / 妨害引用 hero 侧状态行)。
|
||||
# status_table 显式入参:装载序上本校验先于成员赋值执行(self.status_effects 尚为 Nil)——装载通道传 loaded 表,
|
||||
# 冒烟直验传 _db.status_effects;传 null 时 side 守卫跳过(其他校验不受影响)。
|
||||
func validate_skill_pool_links(skill_table: SkillTable, enemy_table: EnemyTable, status_table: StatusEffectTable = null) -> Array:
|
||||
# 施放类 side 守卫(buff → 敌方侧状态 / debuff → 主角侧状态,防反向挂接)
|
||||
func _pool_cast_side_errs(skill_table: SkillTable, status_table: StatusEffectTable) -> Array[Dictionary]:
|
||||
var errs: Array[Dictionary] = []
|
||||
var skill_types := {}
|
||||
for row in skill_table.rows:
|
||||
skill_types[String(row.get("skill_id", ""))] = String(row.get("type", ""))
|
||||
# 施放类 side 守卫:buff → 敌方侧状态 / debuff → 主角侧状态,防反向挂接
|
||||
for row in skill_table.rows:
|
||||
var st: String = String(row.get("type", ""))
|
||||
if st != "buff" and st != "debuff":
|
||||
@@ -133,6 +130,15 @@ func validate_skill_pool_links(skill_table: SkillTable, enemy_table: EnemyTable,
|
||||
var srow: Dictionary[Variant, Variant] = status_table.row_by_id(eff) if status_table != null else {}
|
||||
if not srow.is_empty() and String(srow.get("target_side", "")) != want_side:
|
||||
errs.append({"category": "cast_side", "message": "SkillTable %s(%s)引用 %s 的 target_side=%s ≠ %s(施放类 side 守卫)" % [String(row.get("skill_id", "")), st, eff, String(srow.get("target_side", "")), want_side]})
|
||||
return errs
|
||||
|
||||
|
||||
func validate_skill_pool_links(skill_table: SkillTable, enemy_table: EnemyTable, status_table: StatusEffectTable = null) -> Array:
|
||||
var errs: Array[Dictionary] = []
|
||||
var skill_types := {}
|
||||
for row in skill_table.rows:
|
||||
skill_types[String(row.get("skill_id", ""))] = String(row.get("type", ""))
|
||||
errs.append_array(_pool_cast_side_errs(skill_table, status_table)) # 施放类 side 守卫(buff→敌方侧/debuff→主角侧,防反向挂接——全表恰一次)
|
||||
for row in enemy_table.rows:
|
||||
var eid: String = String(row.get("enemy_id", ""))
|
||||
var basic_n := 0
|
||||
|
||||
@@ -106,7 +106,7 @@ func cap_ok(kind: String, feat_id: String = "") -> bool:
|
||||
return int(taken.get(kind, 0)) < cap
|
||||
|
||||
|
||||
# 专长凭证展示判定(四口径:一局限购一次/罕见只在概率不在价格/计步保底/触发清零。
|
||||
# 专长凭证展示判定(四口径:一局限购一次/稀有只在概率不在价格/计步保底/触发清零。
|
||||
# 调用即一次展示判定与记账——展示次数计 pity、配额与限购双闸)
|
||||
func feat_ticket_consider(rg: RandomNumberGenerator) -> bool:
|
||||
if ticket_sold >= int(db.adventure.feat_ticket_limit):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## EffectContext——效果引擎四桶计数器引用束(无状态引擎的外部状态承载)。
|
||||
## 四桶按生命周期分:round(轮始整桶清空)/battle(随编排器生灭)/level(随 LevelRunner 生灭)/
|
||||
## adventure(随冒险应用层生灭——拆件批桶归宿主字典)。本类零方法零行为,只持引用;桶容器由宿主对象 new,本类只挂引用。
|
||||
## adventure(随冒险应用层生灭——桶归宿主字典)。本类零方法零行为,只持引用;桶容器由宿主对象 new,本类只挂引用。
|
||||
class_name EffectContext
|
||||
extends RefCounted
|
||||
|
||||
|
||||
+38
-27
@@ -80,22 +80,7 @@ func spawn(level_index: int, node_depth: int, hero_hp: int, unit_count_overrides
|
||||
var eovr: int = int(enemy_atk_overrides[row_i]) if row_i < enemy_atk_overrides.size() else -1
|
||||
for i in range(per_row_counts[row_i]):
|
||||
var eff_row_atk: int = eovr if eovr >= 0 else int(row.atk)
|
||||
# 实例池快照(proposal §2.2:开战把模板快照一份,冷却全零——与"生成拿到当时的表值快照"同一条快照纪律)
|
||||
var pool_snap: Array[Dictionary] = []
|
||||
for entry in row.get("pool", []):
|
||||
var snap_entry := {
|
||||
"skill_id": String(entry.get("skill_id", "")),
|
||||
"weight": int(entry.get("weight", 0)),
|
||||
"cooldown_left": 0,
|
||||
}
|
||||
# 触发条件(拆件批随迁:技能行 trigger 是字段权威——快照随读;带 latch 行写单向闩标记
|
||||
# trigger_latched 初始锁定;缺省无 trigger=无条件技)
|
||||
var srow_snap: Dictionary[Variant, Variant] = db.skill_row(String(entry.get("skill_id", "")))
|
||||
if srow_snap.has("trigger"):
|
||||
snap_entry["trigger"] = (srow_snap.get("trigger", {}) as Dictionary).duplicate(true)
|
||||
if bool((snap_entry["trigger"] as Dictionary).get("latch", false)):
|
||||
snap_entry["trigger_latched"] = false
|
||||
pool_snap.append(snap_entry)
|
||||
var pool_snap: Array[Dictionary] = _pool_snapshot(row) # 实例池快照(开战模板快照——纪律见助手头注)
|
||||
_enemies.append({
|
||||
"handle_id": handle,
|
||||
"enemy_id": String(row.enemy_id),
|
||||
@@ -119,6 +104,26 @@ func spawn(level_index: int, node_depth: int, hero_hp: int, unit_count_overrides
|
||||
return true
|
||||
|
||||
|
||||
# 实例池快照(proposal §2.2:开战把模板快照一份,冷却全零——与"生成拿到当时的表值快照"同一条
|
||||
# 快照纪律。触发条件:技能行 trigger 是字段权威——快照随读;带 latch 行写单向闩标记
|
||||
# trigger_latched 初始锁定;缺省无 trigger=无条件技)
|
||||
func _pool_snapshot(row: Dictionary) -> Array[Dictionary]:
|
||||
var pool_snap: Array[Dictionary] = []
|
||||
for entry in row.get("pool", []):
|
||||
var snap_entry := {
|
||||
"skill_id": String(entry.get("skill_id", "")),
|
||||
"weight": int(entry.get("weight", 0)),
|
||||
"cooldown_left": 0,
|
||||
}
|
||||
var srow_snap: Dictionary[Variant, Variant] = db.skill_row(String(entry.get("skill_id", "")))
|
||||
if srow_snap.has("trigger"):
|
||||
snap_entry["trigger"] = (srow_snap.get("trigger", {}) as Dictionary).duplicate(true)
|
||||
if bool((snap_entry["trigger"] as Dictionary).get("latch", false)):
|
||||
snap_entry["trigger_latched"] = false
|
||||
pool_snap.append(snap_entry)
|
||||
return pool_snap
|
||||
|
||||
|
||||
func query_alive(side: String) -> Array:
|
||||
if _despawned:
|
||||
_diag("Despawned 句柄查询(域闭)")
|
||||
@@ -142,20 +147,12 @@ func _entry_blocked(e: Dictionary, u: Dictionary, facts: Dictionary) -> bool:
|
||||
return false
|
||||
if e.has("trigger_latched") and bool(e.get("trigger_latched", false)):
|
||||
return false # 闩已过——不再拦(治疗抬血不回锁)
|
||||
var t: Dictionary = e.get("trigger", {})
|
||||
var t: Dictionary[Variant, Variant] = e.get("trigger", {})
|
||||
var fact := String(t.get("fact", ""))
|
||||
var op := String(t.get("op", ""))
|
||||
var value: Variant = t.get("value", 0)
|
||||
# 自类百分比事实(容器内直读——阈值式折算)
|
||||
if fact == "self_hp_pct":
|
||||
var threshold: int = int(round(float(int(u.max_hp)) * float(int(value)) / 100.0))
|
||||
return not _compare(int(u.hp), op, threshold)
|
||||
if fact == "hero_hp_pct":
|
||||
var hrow: Dictionary[Variant, Variant] = _hero
|
||||
if hrow.is_empty():
|
||||
return true # 无主角行——条件假(fail-safe)
|
||||
var hthreshold: int = int(round(float(int(hrow.max_hp)) * float(int(value)) / 100.0))
|
||||
return not _compare(int(hrow.hp), op, hthreshold)
|
||||
if fact == "self_hp_pct" or fact == "hero_hp_pct":
|
||||
return _pct_fact_blocked(fact, value, op, u) # 自类/主角百分比事实(阈值式折算——v1.2)
|
||||
# 全局事实(编排器组包——缺键=拦)
|
||||
if not facts.has(fact):
|
||||
return true
|
||||
@@ -184,6 +181,20 @@ func _compare_str(lhs: String, op: String, rhs: String) -> bool:
|
||||
|
||||
# 可摇集合:冷却已尽的池条目投影 [{skill_id, weight}]。普通攻击冷却恒 0 → 恒非空(空池不可能的结构前提,
|
||||
# 加载校验"每池恰一行普攻"兜底)。hero/失效句柄拒绝。锁定条目(半血未解锁)双面过滤不入。
|
||||
# 百分比事实阈值判定(阈值式 v1.2:先折算绝对阈值 T=round(对应 max_hp × value/100)、
|
||||
# 再以 hp op T 比较——六算子统一在该阈值上定义。self=容器内直读单位行;hero=主角行,
|
||||
# 无主角行=条件假(拦——fail-safe))
|
||||
func _pct_fact_blocked(fact: String, value: Variant, op: String, u: Dictionary) -> bool:
|
||||
if fact == "self_hp_pct":
|
||||
var threshold: int = int(round(float(int(u.max_hp)) * float(int(value)) / 100.0))
|
||||
return not _compare(int(u.hp), op, threshold)
|
||||
var hrow: Dictionary[Variant, Variant] = _hero
|
||||
if hrow.is_empty():
|
||||
return true # 无主角行——条件假(fail-safe)
|
||||
var hthreshold: int = int(round(float(int(hrow.max_hp)) * float(int(value)) / 100.0))
|
||||
return not _compare(int(hrow.hp), op, hthreshold)
|
||||
|
||||
|
||||
func rollable_skills(u: Dictionary, facts: Dictionary = {}) -> Array:
|
||||
if u.is_empty() or _despawned or u.get("is_hero", false):
|
||||
_diag("rollable_skills 失效句柄")
|
||||
|
||||
@@ -44,36 +44,7 @@ func validate() -> Array:
|
||||
if not SKILL_TYPES.has(type):
|
||||
errs.append({"category": "enum", "message": "%s type 未知枚举: %s(域 %s)" % [sid, type, str(SKILL_TYPES)]})
|
||||
continue
|
||||
# trigger(触发条件,可省略——敌人系统 v1.2:四键白名单/词表出域/类型分派/普攻禁配;加载期报错止动)
|
||||
if row.has("trigger"):
|
||||
var trig: Variant = row.get("trigger", null)
|
||||
if not (trig is Dictionary):
|
||||
errs.append({"category": "domain", "message": "%s trigger 须为 {fact,op,value,latch} 字典" % sid})
|
||||
else:
|
||||
var t: Dictionary = trig
|
||||
for tk in t.keys():
|
||||
if not TRIGGER_KEYS.has(String(tk)):
|
||||
errs.append({"category": "domain", "message": "%s trigger 键白名单外: %s" % [sid, str(tk)]})
|
||||
var tf := String(t.get("fact", ""))
|
||||
var top := String(t.get("op", ""))
|
||||
if not TRIGGER_FACTS.has(tf):
|
||||
errs.append({"category": "enum", "message": "%s trigger fact 出域: %s" % [sid, tf]})
|
||||
if not TRIGGER_OPS.has(top):
|
||||
errs.append({"category": "enum", "message": "%s trigger op 出域: %s" % [sid, top]})
|
||||
if TRIGGER_ENUM_FACTS.has(tf) and not (top == "eq" or top == "neq"):
|
||||
errs.append({"category": "domain", "message": "%s trigger 枚举事实 %s 算子限域 eq/neq: %s" % [sid, tf, top]})
|
||||
if tf != "" and TRIGGER_ENUM_FACTS.has(tf):
|
||||
var ev = t.get("value", "")
|
||||
if not (ev is String) or not TRIGGER_ENUM_VALUES.has(String(ev)):
|
||||
errs.append({"category": "domain", "message": "%s trigger 枚举事实 value 越域: %s(域 %s)" % [sid, str(ev), str(TRIGGER_ENUM_VALUES)]})
|
||||
elif TRIGGER_PCT_FACTS.has(tf):
|
||||
var pv := int(t.get("value", 0))
|
||||
if pv < 1 or pv > 99:
|
||||
errs.append({"category": "domain", "message": "%s trigger 百分比事实 value 越域 [1,99]: %d" % [sid, pv]})
|
||||
elif tf != "" and not (t.get("value", 0) is int):
|
||||
errs.append({"category": "domain", "message": "%s trigger 数值事实 value 须整数: %s" % [sid, str(t.get("value", 0))]})
|
||||
if t.has("latch") and not (t.get("latch", false) is bool):
|
||||
errs.append({"category": "domain", "message": "%s trigger latch 须布尔: %s" % [sid, str(t.get("latch", false))]})
|
||||
_validate_trigger(sid, row, errs) # trigger(触发条件,可省略——四键白名单/词表出域/类型分派/普攻禁配;加载期报错止动)
|
||||
if type == "basic" and row.has("trigger"):
|
||||
errs.append({"category": "cross_field", "message": "%s 普攻行禁配 trigger(普攻恒可摇的结构前提)" % sid})
|
||||
# 冷却域(全类型):施放后连续 N 拍不可摇中
|
||||
@@ -83,14 +54,7 @@ func validate() -> Array:
|
||||
# 普通攻击两条域校验锁死特殊性:倍率恒 1、冷却恒 0——想配的就是伤害技(proposal §2.2)
|
||||
if type == "basic":
|
||||
has_basic = true
|
||||
if row.has("damage_mult") and not is_equal_approx(float(row.damage_mult), 1.0):
|
||||
errs.append({"category": "cross_field", "message": "%s 普攻 damage_mult ≠ 1(禁配——要配就是伤害技): %s" % [sid, str(row.damage_mult)]})
|
||||
if row.has("cooldown_beats") and cd != 0:
|
||||
errs.append({"category": "cross_field", "message": "%s 普攻 cooldown_beats ≠ 0(禁配——池恒非空的结构前提): %d" % [sid, cd]})
|
||||
if row.has("buff_ref") or row.has("buff_duration"):
|
||||
errs.append({"category": "cross_field", "message": "%s 普攻不带增益字段" % sid})
|
||||
if row.has("rider_mult"):
|
||||
errs.append({"category": "cross_field", "message": "%s 普攻不带必中附加分量(rider_mult 仅伤害技)" % sid})
|
||||
_validate_basic_row(sid, row, cd, errs)
|
||||
# 伤害技:存倍率不存固定值——伤害 = 施放者攻击基线 × 技能倍率(三乘法链第一乘);
|
||||
# 可选 rider_mult = 必中附加分量(后置加法、不吃骰不出暴击——proposal-status-vocabulary §2)
|
||||
if type == "damage":
|
||||
@@ -136,6 +100,64 @@ func validate() -> Array:
|
||||
return errs
|
||||
|
||||
|
||||
# trigger 域校验(敌人系统 v1.2 触发条件:四键白名单/词表出域/类型分派——枚举事实算子限域 eq/neq
|
||||
# 且 value 限枚举串、百分比事实 value 域 [1,99]、数值事实 value 须整数、latch 须布尔。行缺 trigger
|
||||
# 直返——可省略字段)
|
||||
func _validate_trigger(sid: String, row: Dictionary, errs: Array[Dictionary]) -> void:
|
||||
if not row.has("trigger"):
|
||||
return
|
||||
var trig: Variant = row.get("trigger", null)
|
||||
if not (trig is Dictionary):
|
||||
errs.append({"category": "domain", "message": "%s trigger 须为 {fact,op,value,latch} 字典" % sid})
|
||||
return
|
||||
var t: Dictionary[Variant, Variant] = trig
|
||||
for tk in t.keys():
|
||||
if not TRIGGER_KEYS.has(String(tk)):
|
||||
errs.append({"category": "domain", "message": "%s trigger 键白名单外: %s" % [sid, str(tk)]})
|
||||
_validate_trigger_domain(t, sid, errs)
|
||||
|
||||
|
||||
# trigger fact/op/value/latch 域校验(词表出域与类型分派——报错顺序=报告顺序,分派段单列)
|
||||
func _validate_trigger_domain(t: Dictionary[Variant, Variant], sid: String, errs: Array[Dictionary]) -> void:
|
||||
var tf := String(t.get("fact", ""))
|
||||
var top := String(t.get("op", ""))
|
||||
if not TRIGGER_FACTS.has(tf):
|
||||
errs.append({"category": "enum", "message": "%s trigger fact 出域: %s" % [sid, tf]})
|
||||
if not TRIGGER_OPS.has(top):
|
||||
errs.append({"category": "enum", "message": "%s trigger op 出域: %s" % [sid, top]})
|
||||
if TRIGGER_ENUM_FACTS.has(tf) and not (top == "eq" or top == "neq"):
|
||||
errs.append({"category": "domain", "message": "%s trigger 枚举事实 %s 算子限域 eq/neq: %s" % [sid, tf, top]})
|
||||
_validate_trigger_value(sid, t, tf, errs)
|
||||
if t.has("latch") and not (t.get("latch", false) is bool):
|
||||
errs.append({"category": "domain", "message": "%s trigger latch 须布尔: %s" % [sid, str(t.get("latch", false))]})
|
||||
|
||||
|
||||
# trigger value 类型分派校验(枚举事实 value 限枚举串/百分比事实 value 域 [1,99]/数值事实 value 须整数)
|
||||
func _validate_trigger_value(sid: String, t: Dictionary[Variant, Variant], tf: String, errs: Array[Dictionary]) -> void:
|
||||
if tf != "" and TRIGGER_ENUM_FACTS.has(tf):
|
||||
var ev = t.get("value", "")
|
||||
if not (ev is String) or not TRIGGER_ENUM_VALUES.has(String(ev)):
|
||||
errs.append({"category": "domain", "message": "%s trigger 枚举事实 value 越域: %s(域 %s)" % [sid, str(ev), str(TRIGGER_ENUM_VALUES)]})
|
||||
elif TRIGGER_PCT_FACTS.has(tf):
|
||||
var pv := int(t.get("value", 0))
|
||||
if pv < 1 or pv > 99:
|
||||
errs.append({"category": "domain", "message": "%s trigger 百分比事实 value 越域 [1,99]: %d" % [sid, pv]})
|
||||
elif tf != "" and not (t.get("value", 0) is int):
|
||||
errs.append({"category": "domain", "message": "%s trigger 数值事实 value 须整数: %s" % [sid, str(t.get("value", 0))]})
|
||||
|
||||
|
||||
# 普攻行禁配校验(倍率恒 1、冷却恒 0、不带增益/rider 字段——「池恒非空」的结构前提)
|
||||
func _validate_basic_row(sid: String, row: Dictionary, cd: int, errs: Array[Dictionary]) -> void:
|
||||
if row.has("damage_mult") and not is_equal_approx(float(row.damage_mult), 1.0):
|
||||
errs.append({"category": "cross_field", "message": "%s 普攻 damage_mult ≠ 1(禁配——要配就是伤害技): %s" % [sid, str(row.damage_mult)]})
|
||||
if row.has("cooldown_beats") and cd != 0:
|
||||
errs.append({"category": "cross_field", "message": "%s 普攻 cooldown_beats ≠ 0(禁配——池恒非空的结构前提): %d" % [sid, cd]})
|
||||
if row.has("buff_ref") or row.has("buff_duration"):
|
||||
errs.append({"category": "cross_field", "message": "%s 普攻不带增益字段" % sid})
|
||||
if row.has("rider_mult"):
|
||||
errs.append({"category": "cross_field", "message": "%s 普攻不带必中附加分量(rider_mult 仅伤害技)" % sid})
|
||||
|
||||
|
||||
func row_by_id(skill_id: String) -> Dictionary:
|
||||
for row in rows:
|
||||
if row.get("skill_id", "") == skill_id:
|
||||
|
||||
@@ -755,7 +755,7 @@ rows = [{
|
||||
}]
|
||||
|
||||
; 切片调参登记 v3(2026-09-12 试玩批次 1 触发——F7 流程;C3 GDD F5 对照):
|
||||
; 试玩反馈 = 基线满血全通关(模拟 80%/真人 100%)——难度严重不足,主杠杆 = atk 曲线上调(承伤侧):
|
||||
; 试玩反馈 = 基线满血全冒险成功(模拟 80%/真人 100%)——难度严重不足,主杠杆 = atk 曲线上调(承伤侧):
|
||||
; 4/4/6/4/7 → 7/5/9/6/9(约 +50%);HP 结构调整(D0 24→20 缩短战斗、Boss 130→150 用户拍板可上调)。
|
||||
; D0 注:20 HP 会被首轮盲挖粉尘秒杀(12+9)——回 24(4 轮战斗/承伤 42%,有过程有痛感)。
|
||||
; DND 命名(用户指令):goblin 地精(单拍杂鱼)→ bugbear 熊地精(三拍伏击环——DND 原型即伏击手)→
|
||||
@@ -895,7 +895,7 @@ rows = [{
|
||||
;
|
||||
; 数值修复批·调参二(2026-10-01 新尺 MC 驱动):L1 系八行 atk 2→1(行 15/35/54/77/99/121/144/166;
|
||||
; 行 234 巨蜘蛛巢群主体=L2 域维持)——新尺读数:普通档 v3.4 死因=L1 四连战无治疗夹缝(雷伤 6/8/8
|
||||
; + 杂兵垫刀双压,L1 条件通关 1-2%,0/100 出第一关);完美档战役 50%(L1 93%)。刀位语义=
|
||||
; + 杂兵垫刀双压,L1 条件关卡完成率 1-2%,0/100 出第一关);完美档战役 50%(L1 93%)。刀位语义=
|
||||
; 「危险来自雷,不来自杂兵」:杂兵垫刀减半,雷直伤 6/8/8 维持痛感;L2/L3(atk 3 系)本刀不动。
|
||||
; 全旧带读数随新尺作废重测归本批。
|
||||
; 调参二补充:上述八行 atk 区间 1-3→0-2(中点恒等期望当量锚不变式——atk=1 需区间中点同步 1;0=掷点空刀,保随机手感)。
|
||||
|
||||
@@ -97,7 +97,7 @@ rows = [{
|
||||
}]
|
||||
|
||||
; 减伤墙调参批(2026-09-13,playtest-2026-09-12 报告 Q1 触发——defense_scan 实测墙轮 39%、
|
||||
; 真人局 12/12 轮零承伤满血通关):defense_up magnitude -50 → -30——叠满两层 = -60 减伤帽
|
||||
; 真人局 12/12 轮零承伤满血冒险成功):defense_up magnitude -50 → -30——叠满两层 = -60 减伤帽
|
||||
; (原拟 pool_clamp_lo=-60 被 schema 冻结域拦截,杠杆移至本表);石肤权重 24→16 随批(reward.tres)。
|
||||
; 承伤带对 C3 F4(≤20%/普通场、≤50%/Boss 场)复验责任随批;B3 GDD "-50" 文字同步随下次 B3 修订批。
|
||||
; 格面资源批(2026-09-15):新增 sapped(乏力——weaken 型负向,hero_offense 池,attack_up 镜像;
|
||||
|
||||
@@ -572,7 +572,7 @@ static func _autoplay_battle(runner, settlement, st: Dictionary, logger) -> void
|
||||
# ①标雷误挖:把「封印已证雷」动作直接转成「挖该格」(真人手滑原型:知道是雷、位置点错,
|
||||
# 踩雷吃伤且该雷奖励报废);期望踩雷增量 ≈ 每板已证雷数 × NORMAL_MINE_SLIP_P(目标完美+2/板)
|
||||
# ②安全挖跳过:把「挖已证安全格」动作转成本轮停手(少挖几个正确的雷——信息与推进双损失)
|
||||
# ③卡死赌挖:完美档无已证动作时刷新/停手拖轮次吃敌方垫刀(实证=完美档 41% 通关全败于慢玩
|
||||
# ③卡死赌挖:完美档无已证动作时刷新/停手拖轮次吃敌方垫刀(实证=完美档 41% 冒险成功;全败于慢玩
|
||||
# 垫刀非踩雷)——真人会按概率赌一个边界格(用户实证口径「有些地方因为我看不到数字,也是盲挖
|
||||
# 的」);普通档不刷新(用户自报全程没用刷新),赌挖替代刷新/停手
|
||||
# 失误流 = st.prng(策略流 RNG,种子派生自局种子——同种子逐位可回放;核心七流零消费零扰动)
|
||||
|
||||
Reference in new issue
Block a user