From 6d392eed880b968c1bd076c48f88d8b447d29898 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Tue, 8 Sep 2026 16:48:36 +0200 Subject: [PATCH] feat: extend warren --- warren.lua | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/warren.lua b/warren.lua index 72c4cd1..f4d146c 100644 --- a/warren.lua +++ b/warren.lua @@ -170,9 +170,94 @@ for _ = 1, opts.auto do game:autoStep() end -io.write(game:render(), "\n") +if opts.play then + playLoop(game) +else + io.write(game:render(), "\n") +end + +if meta and opts.auto > 0 and (not game.player:isAlive() or game.won) then + local stats = game:metaStats() + local gained = Meta.renownFor(stats) + local unlocked = Meta.recordRun(meta, stats) + io.write(string.format("run recorded: +%d renown (total %d)\n", gained, meta.renown)) + for _, name in ipairs(unlocked) do + io.write("achievement unlocked: " .. name .. "\n") + end + local report = Morgue.build(game, meta) + local score = Morgue.score(report) + local percentile = Analytics.percentile(meta.leaderboard, score) + local rank = Leaderboard.record(meta.leaderboard, { + score = score, className = report.className, depth = report.deepestDepth, + turn = report.turn, won = report.won, seed = game.seed, + }) + if rank then + io.write(string.format("leaderboard: rank #%d with score %d (beat %.0f%% of prior runs)\n", + rank, score, percentile * 100)) + end +end + +if meta and opts.auto > 0 and not game.player:isAlive() then + Graves.record(meta, game:graveEntry()) + io.write(string.format("a grave is left at depth %d\n", game.deepestDepth)) +end + +if meta then + Meta.save(meta, opts.metaPath) +end + +if opts.exportPath then + local file = io.open(opts.exportPath, "w") + file:write(Export.leaderboardCsv(meta and meta.leaderboard or Leaderboard.new())) + file:close() + io.write("leaderboard exported to " .. opts.exportPath .. "\n") +end + +if opts.exportCompendiumPath then + local file = io.open(opts.exportCompendiumPath, "w") + file:write(Export.compendiumCsv(meta and meta.compendium or Compendium.new())) + file:close() + io.write("compendium exported to " .. opts.exportCompendiumPath .. "\n") +end + +if opts.report then + reportMeta(meta or Meta.new()) +end + +if opts.verify and not opts.load then + if meta then + io.write("replay skipped: verification only covers meta-free runs (see replay.lua)\n") + else + local report = Morgue.build(game) + local matches, mismatchField, score = + Replay.verify(opts.seed, { class = opts.class, mutators = opts.mutators }, opts.auto, report) + if matches then + io.write(string.format("replay verified: seed %d reproduces this run (score %d)\n", opts.seed, score)) + else + io.write(string.format("replay mismatch at '%s': seed %d replayed to a different outcome (score %d)\n", + mismatchField, opts.seed, score)) + end + end +end if opts.save then game:save(opts.save) io.write("saved to " .. opts.save .. "\n") end + +if opts.morguePath and (game.won or not game.player:isAlive()) then + local report = Morgue.build(game, meta) + local file = io.open(opts.morguePath, "w") + file:write(Morgue.format(report)) + file:close() + io.write(string.format("morgue written to %s (score %d)\n", opts.morguePath, Morgue.score(report))) +end + +if challengePreset and opts.auto > 0 then + local satisfied, reason = Challenges.satisfiedBy(challengePreset, game) + if satisfied then + io.write("challenge honored: every requirement was active for this run\n") + else + io.write("challenge broken: " .. reason .. "\n") + end +end