Status partial. Read this first:
- A seed from seedgen cannot be put in the game today. No tool turns its exported rows into a regulation with new
pattern ids. seedgen's README lists what is missing: append the rows under new pattern ids, add
MapPatternSetrows or a DLL pick, give each row the rightpatternSetId, and test in game. - The seeds Eclipse ships are planned by hand. Each one is a vanilla pattern plus a table of port placements. The castle-variants seed planner turns that into regulation rows, maps and events. That route is described below.
- The commands and file formats below were read from the code. The full build was not run for this page. The parts that come from team notes and could not be confirmed in code are marked as notes with their date.
The pieces
| Piece | Where | Job |
|---|---|---|
| Seed config | S:/souls-script-kt/scripts/tools/castle-variants/config/ |
Which seeds exist and what is placed where. |
seeds.py |
same folder | Lists seeds, checks them against each other, helps pick a pattern and clean tiles. |
plan.py |
same folder | Config to a plan: rowlist.tsv (regulation rows), edits.json (map and event edits), plan.json. |
CastleVariants.exe |
built from S:/eclipse-build/tools/dotnet/CastleVariants |
Applies edits.json to the MSB and EMEVD files. |
build.py |
same folder as plan.py |
Runs the whole chain: plan, maps, regulation, port files, shared binders, checks, reports. |
[seed] pool |
the release toml beside the Eclipse DLL | Tells the game which pattern each Nightlord gets. |
The config files
All under config/ in the castle-variants folder.
seeds/seeds.tsv: the seeds, one line each:pattern,name,status(live,next,idea),note. Plan order is file order.seeds/<pattern>/slots.tsv: that seed's placements. Seed 240 still usesconfig/slots.tsv. Columns:slot(attach point, ornight1/night2),class,map,part(MSB part name),op(swap,clone:dx,dz,drop),port(a key ofports.tsv),reward,think,bgm,note,opts. The comment block at the top ofconfig/slots.tsvexplains everyoptskey. A port writtenNEW:<role>is a placeholder: the planner skips it and the vanilla part stays.seeds/<pattern>/tiles.tsv(optional):attach,map,variation,copy,note. Makes the seed's own row load another vanilla tile or variation at that attach point, so the seed edits a tile no other seed shows.seeds/<pattern>/night.tsv(optional): the seed's Day 1 and Day 2 night boss swaps (LotResultPlayAreaParam).ports.tsv: every port, shared by all seeds.poi-variants.tsv: every enemy set a POI tile can show. A POI port set is an added variation of the tile, never an edit of a vanilla one. A slot line names it withvariant=<name>inopts.plan.pyfails a POI line that names no variant, unless the registry lists that tile asin-placefor that seed.
Steps
-
Read the seed rules in Reference. Check the fill with Stan before you build. He picks what goes where.
-
Look at what exists:
py -3.12 -I -B seeds.py list -
For a new seed, find the tiles it shares with other seeds.
<plan dir>/vanilla-parts.jsoncomes from an earlierplan.pyrun.py -3.12 -I -B seeds.py tiles <pattern> --parts <plan dir>/vanilla-parts.json py -3.12 -I -B seeds.py candidates --top 25 --parts <plan dir>/vanilla-parts.jsontileslists attach points that would show another seed's edited parts, with vanilla tiles and variations that show none. Put the picks inconfig/seeds/<pattern>/tiles.tsv. -
Add the seed to
seeds/seeds.tsvand write itsslots.tsv. -
Check the seeds against each other:
py -3.12 -I -B seeds.py check --seed 240,1153,216,280It checks that a boss family sits in at most one seed and at most one boss slot, placeholders, Day 2 bosses, Nightlords and earths, and maps or parts two seeds both edit.
-
Plan. All seeds are planned together, because the game loads one regulation and one map set:
py -3.12 -I plan.py <out dir> [<mod out dir>] --seed 240,1153,216,280--seed alltakes every line ofseeds.tsv. Without--seed, only seed 240 is planned.--no-arenaskips the Boss Arena feed files. -
Apply the map and event edits:
CastleVariants.exe build apply <out dir>/edits.json -
Or run the whole chain with the driver, which does steps 6 and 7 and the rest:
py -3.12 -I build.py <plan dir> <package dir> [--refresh-arena] [--skip-verify] --seed 240,1153,216,280Its steps, from the code:
plan.py;CastleVariants build apply; spot post-steps;Polish applyof the vanilla regulation plusrowlist.tsvinto<package>/mod/regulation.bin;package.py(port files);CastleVariants namesandmatbins; dumps;verify.pyand the reports.--skip-verifystops before the last step. -
Tell the DLL about the seed. A run only gets an Eclipse seed when its Nightlord has an entry in
[seed] poolofdebug-nightreign.release.toml:[seed] pool = [ { nightlord = 6, pattern = 240 }, { nightlord = 9, pattern = 1153 }, ]One entry per Nightlord and per pattern.
don_weight(default 1) is that Nightlord's weight in Deep of Night; 0 keeps it out of Deep of Night. See[seed]in the debug DLL reference. -
Stage it as a release stage and run the release checks. That is the release pipeline's job, not this page's.
The recipe that works on recent bases (note, 2026-11-10)
From the team memory eclipse-seed-planner-recipe. The env variables exist in lib.py and plan.py; the rest is the
note's claim and was not re-run.
- Set
CV_ARENA_BASEto the 0.0.51 release regulation:S:/souls-script-kt/output/eclipse-release-0.0.51/depth6-online-mods/mod/regulation.bin. With it,plan.py --seed 240,1153,216,280runs clean. Without it the run stops on a port-rows file whose copy sources are missing in vanilla;lib.pyprints the hintset CV_ARENA_BASEfor that case. A 0.0.9x regulation as base still fails. - Run a frozen copy of the castle-variants folder inside the stage's
work/, through the build scheduler:eb.py run --mem 2 -- <command>. - Build CastleVariants from source:
eb.py tool build castlevariants_src.tools.tomlsays why: the frozen 0.0.86 binary lacks ops the source has (ungroupand others). - Never ship a from-vanilla rebuild of a map that a later stage changed. A rebuild from vanilla does not reproduce
the published files for 14 maps. Start from the published files and add to them with
CastleVariants build apply. - Night arenas have no per-pattern variation. A night boss swap changes that arena for every pattern that uses it.
Other things plan.py reads from the environment
| Variable | Meaning |
|---|---|
CV_ARENA_BASE |
A release regulation.bin used as the base of the port rows; its rows win. |
CV_MASTER_RELEASE |
Overrides which release's master rows are used; - turns that off. |
CV_DUMP_OVERLAY |
; list of dump folders searched first; the first one receives new dumps. Without it, dumps go to <out dir>/dump. |
CV_ARENA, CV_ARENA_OVERLAYS |
Which Boss Arena package the port files and rows come from. |
CV_SRC_EVD |
Folder of the source EMEVD files (default S:/souls-script-kt/.tmp/castle/nr/event). |
CV_ARENA_PARITY |
verify.py: warn or off relaxes the Boss Arena check. |
How to tell it worked
plan.pyandseeds.py checkend withoutFAILlines.build.pyexits 0;verify.pywrites its report under<package dir>/reports.- In game, a run against a pool Nightlord shows the planned map.
seed-run-log.jsonlbeside the DLL has one line per expedition withrolled,forcedandcommitted. Stan starts the game; never launch it yourself.
What goes wrong
- A second seed shows the first seed's bosses. Field boss tiles and evergaol parts are shared by most patterns. Use
tiles.tsvor added variations. Note (2026-11-06): every launch-era field attach point (750 to 763) has exactly one tile, and seeds 240 and 1153 edit them in place. plan.pyfails a POI line: the line edits a POI tile withoutvariant=. Add the variant topoi-variants.tsv.- A Nightlord whose pattern belongs to another Nightlord has hung loads before. The pool entry's Nightlord must be the
pattern's own (
targetBoss). plan.pyis heavy. Run it througheb.py run --mem, and not while Nightreign is open.