From f683409fb33ead03ce15bca18f1a27be9efde62e Mon Sep 17 00:00:00 2001 From: @permadeath.com Date: Tue, 25 Aug 2026 01:12:52 +0000 Subject: [PATCH] docs(unlocks): an epic for a tech tree generated over the unit library A node is a predicate plus a criterion, so the tree comes from the index rather than from an author. Salvage and how progress is trusted are the two gaps. Co-Authored-By: Claude Opus 5 (1M context) --- plan/README.md | 1 + plan/campaign.md | 7 +++++++ plan/order.txt | 1 + plan/unlocks.md | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 file(s) changed, 111 insertion(s)(+), 0 deletion(s)(-) diff --git a/plan/README.md b/plan/README.md --- a/plan/README.md +++ b/plan/README.md @@ -151,6 +151,7 @@ | [seasons](seasons.md) | A run of days is a season with a theme and an end | blocked | | [after-action](after-action.md) | A finished match is worth reading, not just counting | open | | [campaign](campaign.md) | Pilots and forces persist between matches | open | +| [unlocks](unlocks.md) | A campaign is walked by unlocking the library one design at a time | blocked | | [tournaments](tournaments.md) | A tournament says what may enter, and checks it | blocked | | [house-rules](house-rules.md) | One named set of rules every lance.blue match is played under | open | | [setup-tree](setup-tree.md) | Match setup is one tree, rendered as a lobby and as a scenario file | open | diff --git a/plan/campaign.md b/plan/campaign.md --- a/plan/campaign.md +++ b/plan/campaign.md @@ -61,6 +61,13 @@ guidance elsewhere in atproto that a state change is better than a deletion. +## Related + +[unlocks](unlocks.md) is the other half of what people mean by campaign mode: +progression through the unit library rather than a pilot's history. It is a +separate epic because it has a separate exit criterion, but it inherits this +one's answer to how persistent state is trusted — there should not be two. + ## Done Nothing closed yet. diff --git a/plan/order.txt b/plan/order.txt --- a/plan/order.txt +++ b/plan/order.txt @@ -48,6 +48,7 @@ seasons after-action campaign +unlocks tournaments site-copy diff --git a/plan/unlocks.md b/plan/unlocks.md new file mode 100644 --- /dev/null +++ b/plan/unlocks.md @@ -0,0 +1,102 @@ +--- +id: unlocks +title: A campaign is walked by unlocking the library one design at a time +status: blocked +repos: [headquarters, arena] +dependsOn: [unit-library, match-records, forces, achievements] +exitCriterion: > + A player has a tree over MegaMek's own library, every node has a criterion + generated from the index rather than written by hand, and playing a match + moves them through it. +--- + +# unlocks + +A single-player progression whose tree is the unit library. Every design, +variant and piece of equipment MegaMek knows is a node, and reaching one means +doing something specific in a match: fielding the design before it, salvaging +one, seeing one on the other side, landing a hit with a particular weapon. + +The reason this is worth building here rather than anywhere else is that the +tree already exists as data. [unit-library](unit-library.md) has every design +with its era, tech base, rules level, chassis and equipment, and +[unit-search](unit-search.md) turns any subset of that into a predicate. A node +is a predicate plus a criterion, so the tree can be generated over the whole +library instead of authored — which is the only way a tree with four thousand +Meks in it is ever finished. + +## The tree is generated, not written + +- [ ] **Decide what the edges are.** Chassis to variant is the obvious one; era + to era, tech base to tech base and weight class upward are the others. + All of them are columns the index already carries, which is what makes + the tree derivable in the first place. +- [ ] **Generate it and check it is walkable.** A tree over a real library has + orphans, cycles through renamed chassis, and nodes whose only parent is + an unavailable design. That is a graph check, and it belongs in whatever + builds the tree rather than in a reviewer's head. +- [ ] **Decide how big a step is.** Every variant of every chassis is thousands + of nodes and no shape. A chassis with its variants collapsed behind it is + a tree a player can see the end of. +- [ ] **Pin the tree to a MegaMek release.** The library is keyed to one, and a + tree generated against a different release has nodes a player cannot + reach. Same problem [forces](forces.md) has with art, and it should have + the same answer. + +## The criteria are generated too + +A criterion is a question asked of a finished match. The interesting ones are +the ones nothing records yet. + +- [ ] **Field it.** Answerable from the force a player brought, which + [forces](forces.md) will already know. +- [ ] **See it.** The opposing force is in the match record, so this is + answerable as soon as [match-records](match-records.md) lands. +- [ ] **Salvage it.** Needs a salvage rule, and there is not one — see below. +- [ ] **Do a thing.** Land a melee attack, fire a particular weapon class, + survive an ammunition explosion. These need per-event detail out of the + match, which is [after-action](after-action.md)'s territory, and none of + them can be generated until the vocabulary of events is fixed. +- [ ] **Decide which criteria a node gets from its data.** A design with no + melee weapon cannot be unlocked by using one. Generating a criterion + means generating one the node's own facets can satisfy, so this is a + constraint solver over the index and not a template. +- [ ] **Keep the generated criteria few and named.** A criterion nobody can + state in one sentence is a criterion a player will not aim at, and one + more shape of question for every consumer to implement. + +## What it needs that does not exist + +- [ ] **Salvage.** Nothing in the project has a notion of taking a wreck home. + It is the criterion the tree most wants and the one with the most rules + behind it — ask jmm what salvage means before designing anything that + uses the word. +- [ ] **Decide what a player's progress is.** It is durable, player-owned state + and it is worth falsifying, which is exactly [campaign](campaign.md)'s + trust problem. Whatever answer that epic reaches, this uses it; a second + answer here would mean two kinds of progress with two credibilities. +- [ ] **Decide whether an unlock gates anything.** A tree that only records + what a player has done is an achievement wall. + A tree that decides what they may field is a game mode, and it needs + [forces](forces.md) to enforce it and a place in + [setup-tree](setup-tree.md) where an unlocked-only match is a match type. + These are different features and the first is a prerequisite of the + second. +- [ ] **Decide how it relates to awards.** [achievements](achievements.md) + already issues, verifies and displays "the player did a thing", and a + node reached is that. Reusing it means the tree is a view over awards + rather than a second ledger; not reusing it means saying why. + +## Not this epic + +**Not MekHQ.** A campaign layer with contracts, repair bays and a payroll is +[declined](declined.md), and a progression tree is not a way to arrive at one +sideways. + +**Not multiplayer progression.** Unlocks are single-player. A tree that decides +what a player may bring to a match against somebody else is a matchmaking +constraint and would have to answer to [tournaments](tournaments.md). + +## Done + +Nothing closed yet. -- tangled.sh