85 lines
3.5 KiB
GDScript
85 lines
3.5 KiB
GDScript
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||
# playtest-2026-09-12 Q1 复核——"安全格减伤是否过量导致满血打完 Boss"
|
||
# 口径:逐结算轮统计 ac_up 授予层数(AC10→11→12)与该轮敌方实伤,
|
||
# 分割"高 AC 轮"(叠满 = AC12,期望减免 28.75%)与基线轮(AC10,期望减免 21.25%)的承伤读数。
|
||
# 运行:Godot_console.exe --headless --path . --script res://sim/defense_scan.gd -- [N] [seed0]
|
||
extends SceneTree
|
||
|
||
|
||
func _initialize() -> void:
|
||
var args := OS.get_cmdline_user_args()
|
||
var n := 8
|
||
if args.size() >= 1 and args[0].is_valid_int():
|
||
n = maxi(2, int(args[0]))
|
||
var seed0 := 42
|
||
if args.size() >= 2 and args[1].is_valid_int():
|
||
seed0 = int(args[1])
|
||
var db = load("res://core/config_db.gd").new()
|
||
if not db.load_tables("res://data/tables", false):
|
||
print("表加载失败")
|
||
quit(1)
|
||
return
|
||
var autoplay = load("res://sim/level_autoplay.gd")
|
||
print("=== 盾牌加护叠层扫描(AC 口径):第一关 · N=%d · 种子 %d+%d ===" % [n, seed0, n])
|
||
print("%-6s %-6s %-8s %-12s %-14s %-14s" % ["seed", "轮数", "战斗轮", "满层轮(AC12)", "满层轮承伤", "非满层轮承伤"])
|
||
var full_rounds := 0
|
||
var open_rounds := 0
|
||
var full_dmg := 0
|
||
var open_dmg := 0
|
||
var stack_total := 0
|
||
var combat_rounds := 0
|
||
for i in range(n):
|
||
var st = autoplay.run_level(db, seed0 + i, 1, 0, 0, true)
|
||
# 逐轮聚合(按战斗分段——round_index 跨战斗重置,直接用轮号会串桶):
|
||
# effect 行 effect_id=ac_up 计盾牌加护层;enemy_action damage 计承伤
|
||
var ac_by_round := {}
|
||
var dmg_by_round := {}
|
||
var battle_seq := 0
|
||
var last_round := 0
|
||
for row in st.rows:
|
||
var r: int = int(row.get("round_index", 0))
|
||
if r < last_round:
|
||
battle_seq += 1 # 轮号回卷 = 新战斗
|
||
last_round = r
|
||
var key := battle_seq * 1000 + r
|
||
if String(row.get("type", "")) == "effect" and String(row.get("effect_id", "")) == "ac_up" \
|
||
and String(row.get("source_class", "")) == "safe_cell":
|
||
ac_by_round[key] = int(ac_by_round.get(key, 0)) + 1
|
||
elif String(row.get("type", "")) == "damage" and String(row.get("source_class", "")) == "enemy_action":
|
||
dmg_by_round[key] = int(dmg_by_round.get(key, 0)) + int(row.get("value", 0))
|
||
for k in ac_by_round:
|
||
combat_rounds += 1
|
||
stack_total += int(ac_by_round[k])
|
||
var d: int = int(dmg_by_round.get(k, 0))
|
||
if int(ac_by_round[k]) >= 2:
|
||
full_rounds += 1
|
||
full_dmg += d
|
||
else:
|
||
open_rounds += 1
|
||
open_dmg += d
|
||
print("%-6d %-6d %-8d %-12d %-14s %-14s" % [seed0 + i, st.rounds, ac_by_round.size(),
|
||
_full_count(ac_by_round), str(dmg_in(dmg_by_round, ac_by_round, 2)), str(dmg_in(dmg_by_round, ac_by_round, 1))])
|
||
if combat_rounds > 0:
|
||
print("---- 战斗轮 %d:满层轮 %d(%.0f%%,均值 %.2f 层/轮)· 满层轮承伤合计 %d(AC12——期望减免 28.75%%)· 非满层轮承伤合计 %d(均 %.1f/轮,AC10/11)" % [
|
||
combat_rounds, full_rounds, 100.0 * float(full_rounds) / float(combat_rounds),
|
||
float(stack_total) / float(combat_rounds), full_dmg, open_dmg, float(open_dmg) / float(maxi(1, open_rounds))])
|
||
quit(0)
|
||
|
||
|
||
func _full_count(ac_by_round: Dictionary) -> int:
|
||
var c := 0
|
||
for r in ac_by_round:
|
||
if int(ac_by_round[r]) >= 2:
|
||
c += 1
|
||
return c
|
||
|
||
|
||
func dmg_in(dmg_by_round: Dictionary, ac_by_round: Dictionary, mode: int) -> int:
|
||
# mode=2 满层轮承伤 / mode=1 非满层轮承伤
|
||
var t := 0
|
||
for r in ac_by_round:
|
||
var full: bool = int(ac_by_round[r]) >= 2
|
||
if (mode == 2 and full) or (mode == 1 and not full):
|
||
t += int(dmg_by_round.get(r, 0))
|
||
return t
|