feat(迭代27 T5): 波五a 类型闸拉起+存量收口——审计器 0 存量+warning 配置在位

P1-6 类型闸(须 T1-T4 全落后——本波按执行顺序锁殿后):
- tools/audit_type_hints.py 新机器闸(V7): R1 无类型容器注解/R2 有值返回缺返回类型/
  R3 参数缺类型三规则+行级 # type-hint: ignore 显式白名单通道;产品码 core/data/presentation
- 存量收口: 368 处显式 Array/Dictionary 非参数化注解→机械参数化(Array[Variant]/
  Dictionary[Variant, Variant] 零行为面);13 处参数真类型(SaveManagerCore/ConfigDb/
  BattleOrchestrator/MinesweeperRules/LevelRunner/SettingsStore 等)
- 白名单豁免四处: board_generator generate/_attempt/legality/_finalize 的 db 参——
  测量面 _BoardRowStub 冒烟夹具鸭子型注入(typed 参拒 stub)
- project.godot 拉起 gdscript/warnings/untyped_declaration=1(V7 源码断言在 smoke _smoke_type_gate)
- static_scan 新 S9 类型闸规则;顺修历史 cd 错位(9-24 布局迁移后 /.. 落 game/ 致守卫
  恒跳过静默空转——修复后 S1-S4/S9 首次实跑全绿)+S1/S2 增 ADR-0007-exempt 标记豁免通道
  (main _seed_value 引擎熵源=文档化豁免面)

验收: 冒烟 1081/0(+V7×2)+run_all 27 套+static_scan 全绿+probe click+render golden+对拍三变体全同
This commit is contained in:
DKChan committed 2026-10-15 01:05:17 +08:00
1 parent 8b9e55673f
commit b605022001
58 files changed
+503 -384

No files matched your search

+21 -21
View File
@@ -113,7 +113,7 @@ func _fx_fact(fact: String):
"dig_streak":
return dig_streak
"hp_ratio":
var hu: Dictionary = units.hero_unit()
var hu: Dictionary[Variant, Variant] = units.hero_unit()
return int(round(100.0 * float(int(hu.get("hp", 0))) / float(maxi(1, int(hu.get("max_hp", 1)))))) # 百分比 int(when lte int 截断口径)
return null
@@ -292,9 +292,9 @@ func _hero_attack_ctx(t: Dictionary) -> Dictionary:
var armor: String = String(target.get("armor_type", "light"))
var atk_type: String = String(t.attack_type)
var matchup := (atk_type + "_vs_" + armor) if atk_type != "" else ""
var ac_hits: Array = (t.context.get("fx_attack_hits", []) as Array)
var ac_payload: Dictionary = (t.context.get("fx_attack_payload", {}) as Dictionary)
var roll_read: Dictionary = _armor_roll()
var ac_hits: Array[Variant] = (t.context.get("fx_attack_hits", []) as Array)
var ac_payload: Dictionary[Variant, Variant] = (t.context.get("fx_attack_payload", {}) as Dictionary)
var roll_read: Dictionary[Variant, Variant] = _armor_roll()
var threshold: int = defender_ac(target) + int(db.settlement.attack_bonus)
# armor_roll 发射点(内容数据驱动扩展批 T1——敌护甲掷骰判定;免掷恒折扣订阅面)
var ar_hits := _fx_hits("armor_roll", {"target_ac": threshold, "roll": int(roll_read.roll)})
@@ -349,8 +349,8 @@ func _hero_attack_ctx(t: Dictionary) -> Dictionary:
# 基值装配(原 :329-355 逐字):基值+单位标记加伤+矿工重锤增伤面+加法族(attack_bonus/
# value_counter 层值)+计数器施加(attack_commit 用后清零行——命中序=声明序)+spike 倍乘。
func _hero_attack_base_value(t: Dictionary, ctx: Dictionary) -> float:
var ac_hits: Array = ctx["ac_hits"]
var ac_payload: Dictionary = ctx["ac_payload"]
var ac_hits: Array[Variant] = ctx["ac_hits"]
var ac_payload: Dictionary[Variant, Variant] = ctx["ac_payload"]
var base_value := float(t.base_value)
# 单位标记加伤(迭代 20 T1——处刑台 target_attack_bonus 挂单位字典 fx_atk_bonus 键;
# 阈值沿发射点已写入,本处通用消费——对该敌伤害加算)
@@ -385,11 +385,11 @@ func _hero_attack_base_value(t: Dictionary, ctx: Dictionary) -> float:
# 击杀标记/kill 发射+贯穿弹射。返回 {landed, payload, hero_rider}(交付步消费)。
func _hero_attack_redeem(t: Dictionary, ctx: Dictionary, base_value: float) -> Dictionary:
var target = ctx["target"]
var ac_hits: Array = ctx["ac_hits"]
var roll_read: Dictionary = ctx["roll_read"]
var ac_hits: Array[Variant] = ctx["ac_hits"]
var roll_read: Dictionary[Variant, Variant] = ctx["roll_read"]
var atk_type: String = ctx["atk_type"]
var rolled: int = DamageMath.rolled_component(base_value, int(ctx["discount"]), bool(ctx["crit"]), int(db.settlement.crit_multiplier), int(ctx["cdelta"]))
var payload: Dictionary = {"target": String(target.display_name)}
var payload: Dictionary[Variant, Variant] = {"target": String(target.display_name)}
payload[atk_type] = rolled # 分量键 = 实际攻击类型(归因字段,单分量模型)
payload["roll"] = int(roll_read.roll)
payload["ac"] = int(ctx["threshold"])
@@ -440,7 +440,7 @@ func _hero_attack_redeem(t: Dictionary, ctx: Dictionary, base_value: float) -> D
# 交付(原 :403-414 逐字):即时执行族(碎甲震击护甲裂解)/标签装配/明细行发射/兑现登记。
func _hero_attack_deliver(t: Dictionary, ctx: Dictionary, redemption: Dictionary) -> void:
var payload: Dictionary = redemption["payload"]
var payload: Dictionary[Variant, Variant] = redemption["payload"]
# 即时执行族:碎甲震击打重甲附加「护甲裂解」(复用 off_guard——零新状态行;apply_effect 域闭/
# 重复授予由状态容器自行守卫)
for h in (ctx["ac_hits"] as Array):
@@ -459,8 +459,8 @@ func _hero_attack_deliver(t: Dictionary, ctx: Dictionary, redemption: Dictionary
# 前态恒中性 delta 0,写法同 hero_attack 的 _counter_delta 消费位)→ hero_defense×enemy_output
# 池乘区 → 下限 → +rider(后置必中附加)→ 交付 → commit_action(作废单不 commit——死亡即不动手)
func _resolve_enemy_skill(t: Dictionary) -> void:
var hero: Dictionary = units.hero_unit()
var roll_read: Dictionary = _armor_roll()
var hero: Dictionary[Variant, Variant] = units.hero_unit()
var roll_read: Dictionary[Variant, Variant] = _armor_roll()
var threshold: int = defender_ac(hero) + int(db.settlement.attack_bonus)
var crit: bool = bool(roll_read.crit)
var discount: int = _roll_discount(int(roll_read.roll), threshold)
@@ -489,7 +489,7 @@ func _resolve_enemy_skill(t: Dictionary) -> void:
if shield > 0:
total = maxi(int(db.settlement.damage_floor), total - shield)
units.apply_damage(hero, total)
var payload: Dictionary = {"target": "hero", "skill_id": String(t.context.get("skill_id", "")), "baseline": int(t.context.get("baseline", 0)),
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_read.roll), "ac": threshold, "tier": discount, "attack_type": String(t.attack_type)}
if crit:
payload["crit"] = true
@@ -529,7 +529,7 @@ func _resolve_board_typed(t: Dictionary) -> void:
# 棋盘群伤:无类型恒定表值,结账时刻全体存活敌逐个交付(单行汇总——行内 count = 兑现时存活数)
func _resolve_board_blast(t: Dictionary) -> void:
var alive: Array = units.query_alive("enemy")
var alive: Array[Variant] = units.query_alive("enemy")
if alive.is_empty():
_ineffective_row(t, "无存活敌人")
_outcomes[int(t.ticket_id)] = "zero"
@@ -546,7 +546,7 @@ func _resolve_board_blast(t: Dictionary) -> void:
func _resolve_board_flat_hero(t: Dictionary) -> void:
var dealt: int = maxi(int(db.settlement.damage_floor), int(t.base_value)) # 伤害下限全来源(2026-09-20)
units.apply_damage(units.hero_unit(), dealt)
var extra: Dictionary = {"target": "hero"}
var extra: Dictionary[Variant, Variant] = {"target": "hero"}
for k in t.context.keys():
extra[k] = t.context[k]
emit_row_cb.call("damage", String(t.source_class), t.origin_cell, int(t.round_index), "%s → 主角" % String(t.display), dealt, extra, String(t.highlight))
@@ -578,13 +578,13 @@ func defender_ac(unit: Dictionary) -> int:
if total < 0:
total = int(db.hero.armor_class)
for eff in effects.query_active("hero"):
var row: Dictionary = db.status_effect_row(eff.effect_id)
var row: Dictionary[Variant, Variant] = db.status_effect_row(eff.effect_id)
if not row.is_empty() and String(row.unit) == "ac":
total += int(eff.effective_value)
return total
var total_e: int = int(unit.get("armor_class", 0))
for eff_e in effects.query_active("enemy"):
var erow_ac: Dictionary = db.status_effect_row(eff_e.effect_id)
var erow_ac: Dictionary[Variant, Variant] = db.status_effect_row(eff_e.effect_id)
if not erow_ac.is_empty() and String(erow_ac.unit) == "ac":
total_e += int(eff_e.effective_value)
return total_e
@@ -595,14 +595,14 @@ func defender_ac(unit: Dictionary) -> int:
func _counter_delta(attack_type: String, armor: String) -> int:
if attack_type == "":
return 0
var tbl: Dictionary = db.settlement.armor_effectiveness
var row: Dictionary = tbl.get(attack_type, {})
var tbl: Dictionary[Variant, Variant] = db.settlement.armor_effectiveness
var row: Dictionary[Variant, Variant] = tbl.get(attack_type, {})
return int(row.get(armor, 0))
# 折扣档改善(迭代 12 T4 猎弱本能——折扣表向全额方向移 value 档;查不到当前档 = 不动防御口径)
func _discount_shift_up(discount: int, shift: int) -> int:
var tbl: Array = db.settlement.roll_tier_discounts
var tbl: Array[Variant] = db.settlement.roll_tier_discounts
var idx := tbl.find(discount)
if idx < 0:
return discount
@@ -613,7 +613,7 @@ func _discount_shift_up(discount: int, shift: int) -> int:
func clamped_pool(pool: String) -> int:
var total := 0
for eff in effects.query_active("hero") + effects.query_active("enemy"):
var row: Dictionary = db.status_effect_row(eff.effect_id)
var row: Dictionary[Variant, Variant] = db.status_effect_row(eff.effect_id)
if row.is_empty():
continue
if String(db.settlement.effect_pool_map.get(eff.effect_id, "")) == pool and String(row.unit) == "percent":