Web frontend and supporting services for lance.blue
headquarters plan setup-tree.md
7.5 kB


id: setup-tree title: Match setup is one tree, rendered as a lobby and as a scenario file status: open repos: [headquarters, arena] dependsOn: [lobby] exitCriterion: > A new kind of match is a new tree, and neither the lobby nor the .mms writer needs a branch for it. #

setup-tree #

A direction jmm sketched, not a decision. Locking is the right idea, but it wants to be AST-like rather than a flag per setting: Locked(Choice(x, y, z)), so that lobby logic is something to iterate on quickly instead of something to rewrite per feature.

What is behind it: a daily challenge is not a match type. It is a scenario plus a set of locked lobby settings — the scenario is fixed, both seats are fixed, chat is gone. Everything distinctive about it is a control a player would otherwise have, taken away. Duel is the same trick weaker: a Choice over two-slot scenarios where Scenario has a Choice over the whole catalog.

The shape #

A value that is free, Locked(x), Choice(a, b, c), and Locked(Choice(…)) as the composition — a tutorial that offers force A, B or C and nothing else.

One tree, two renderings. The lobby greys out what is locked and offers what is a choice; the .mms writer emits whatever the tree resolved to. A scenario kind — tutorial, co-op, weekly, ladder — is then a tree rather than a code path, and the fourth one costs a tree rather than a fourth branch in lobbyScreen.

What a V1 file can already lock #

crates/mms reads and writes MMSVersion=1, so this part needs no new format work. Checked against ScenarioV1.java and MegaMekGUI.java in MegaMek 0.51.0:

  • SinglePlayer=true skips both setup dialogs — player assignment and host — and makes every faction after the first a bot.
  • FixedGameOptions=true skips the Game Options dialog. GameOptionsFile= names the ruleset it would otherwise have asked for.
  • FixedPlanetaryConditions=true skips the Planetary Conditions dialog.
  • team_<faction>, Location_<faction> and camo_<faction> fix a faction's team, deployment edge and paint.

The case of those three is a trap, and whatever writes them has to know it. ScenarioV1.getFactionParam is param + "_" + faction, and the constants are team and camo lower case but Location capitalised — so Team_X and Camo_X are read as nothing and dropped in silence. crates/mms already reports that as a Quirk. Omitting team_ is not neutral either: MegaMek then gives every faction its own team.

Deployment edges are IStartingPositions.START_LOCATION_NAMES, which carries CTR alongside the compass points, so a fixed centre deployment is already expressible.

What V1 cannot express and V2 can #

  • A per-player bot: node — Princess's behaviour. MegaMek ships 14 named presets in mmconf/princessBehaviors.xml (Striker, Scout, Brawler, …), and which bot you are fighting is exactly the sort of thing a tree would want to lock or to offer.
  • Board files resolved relative to the scenario file, multi-board and embed, postprocess terrain edits, and hex-area deployment rather than an edge.

So the V2 migration belongs to this epic rather than being a separate format chore: the tree wants nodes V1 has no line for.

arena has to catch up either way. MatchHost.java builds new Princess(p.getName(), LOCALHOST, a.port) and never consults the scenario, so a bot: node today is ignored rather than broken. That is a safe order to do it in, but it means "arena reads the scenario and applies what it says" is this epic's work too, not a one-off.

What neither can express #

Equipment modes. Nothing in either loader sets one, so stealth armour cannot be switched on at scenario start — Mek.isStealthActive wants curMode().equals("On") and hasActiveECM(). A tree offering "stealth on" would be promising something the file cannot carry, so either arena applies it after load or the node does not exist.

Still open #

  • `content/overrides.ts` already splits its own list this way, with a
    `Disclosure` of `"visible" | "silent"` and a `VISIBLE_RULES` set deciding
    which is which. That is the same distinction arrived at from the other
    end, and the tree should carry it as a property of a node rather than
    leaving each renderer to keep its own list of what is worth mentioning.
    

Open questions #

lobby is what would be rendered from the tree, and its Duel-is-only-a-filter note is the same observation from the other side. scenarios is the file the writer emits; daily-challenge is the first tree, written by hand.

Done #

  • The lobby's columns follow it live, so moving a seat regroups the
    screen — which is the whole point for Monte Diablo, whose description
    reads like an alliance. Changing it drops every readiness in the
    lobby, which falls out of going through `broadcast_seats` and is the
    right answer anyway: who is allied with whom is exactly what somebody
    who already pressed Ready should be asked about again.
    
    This is the first node of the tree this epic is about, built as a node
    rather than as a flag: free in an ordinary lobby, and fixed in a daily,
    which renders a pill instead of a control because its sides *are* the
    challenge.