magicciv/public/resources/start_scripts/start_scripts.schema.json
Natalie ac019c0607 refactor(@projects/@magic-civilization): 🎨 shared PanelModal theme variations replace 4 inline modal styleboxes (p2-87)
Extend the type-variation pipeline to emit StyleBox variations, then dedup the
repeated "modal panel" stylebox (bg=background.panel, border=border.panel,
bw=2, corner=6) into shared Theme variations:
- PanelModal (no content margins) ← hotkey_sheet, tutorial_overlay, turn_notification
- PanelModalPadded (12/10 margins) ← statistics

4 inline StyleBoxFlat builds → theme_type_variation inheritance. Value-preserving
(variation stylebox == the inline geometry/colours). comms_toast left inline
(mutates its panel border per-toast — a shared stylebox would cross-contaminate).

Verified: PanelModal/Padded baked into ui_theme.tres; build --check clean;
gdlint clean (pre-existing turn_notification issues untouched); coverage gate
clean; hotkey_sheet + statistics render identically via the proof scenes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 11:03:08 -05:00

171 lines
9.3 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "start_script",
"title": "Game-start script",
"description": "Declarative opening sequence for a game. The bundled default (default_dwarf_tribe) reproduces the freepeople tribe-founding prologue; scenario-makers author their own and point setup.json:start_script at the file id. The runner lives in Rust (mc-turn::start_script); this script is content. Every op maps to an existing simulation primitive — the runner sequences, it does not add new behaviour.",
"type": "object",
"additionalProperties": false,
"required": ["id", "schema_version", "actors", "phases"],
"properties": {
"id": {
"type": "string",
"description": "Unique script id; matches the filename stem and the value of setup.json:start_script.",
"pattern": "^[a-z0-9_]+$"
},
"schema_version": {
"type": "integer",
"description": "Schema version this script targets. Current: 1.",
"const": 1
},
"label": {
"type": "string",
"description": "Human-readable name shown in scenario/new-game UI."
},
"description": {
"type": "string",
"description": "What this opening does, for the scenario picker."
},
"rng_domain": {
"type": "string",
"description": "SeedDomain tag for this script's PRNG substream — keeps it disjoint from worldgen/other streams. Default: 'start_script'.",
"default": "start_script"
},
"actors": {
"type": "array",
"description": "Actor archetypes the ops reference by tag (e.g. the wanderers that converge, the tribe unit they become).",
"items": { "$ref": "#/$defs/actor" }
},
"params": {
"type": "object",
"description": "Named tunables that ops reference via *_ref. Each resolves a value (today: from a setup.json key via from_setup) so a scenario retunes counts/mode/radius without editing ops.",
"additionalProperties": { "$ref": "#/$defs/param" }
},
"phases": {
"type": "array",
"description": "Ordered scripted turns. The runner is at one phase at a time; End Turn resolves the current phase and enters the next. Must contain at least one phase of kind 'normal' (the hand-off to normal play).",
"minItems": 1,
"items": { "$ref": "#/$defs/phase" }
}
},
"$defs": {
"actor": {
"type": "object",
"additionalProperties": false,
"required": ["tag", "unit_id"],
"properties": {
"tag": { "type": "string", "description": "Reference name used by ops (e.g. 'wanderer', 'tribe')." },
"unit_id": { "type": "string", "description": "Unit definition id this actor instantiates (must exist in the unit catalog)." },
"controlled": { "type": "boolean", "default": false, "description": "True if the player commands this actor (e.g. the tribe on the hand-off turn)." }
}
},
"param": {
"type": "object",
"additionalProperties": false,
"required": ["from_setup"],
"properties": {
"from_setup": { "type": "string", "description": "setup.json key whose value this param resolves to." }
}
},
"phase": {
"type": "object",
"additionalProperties": false,
"required": ["id", "display_turn", "kind"],
"properties": {
"id": { "type": "string", "description": "Phase id; used in validator error messages." },
"display_turn": { "type": "integer", "description": "Turn counter the HUD shows during this phase (need not be contiguous or monotonic)." },
"kind": {
"type": "string",
"enum": ["prologue", "normal"],
"description": "'prologue' = input-gated scripted turn; 'normal' = hand-off marker (its on_enter runs, then normal play takes over)."
},
"banner_key": { "type": "string", "description": "ThemeVocabulary key for the centered banner shown this phase." },
"banner_persist": { "type": "boolean", "description": "True = banner stays until the next phase; false = auto-dismiss. Default: true for 'prologue', false for 'normal'." },
"allowed_actions": {
"type": "array",
"items": { "type": "string" },
"description": "Player input gate for this phase. Default: ['end_turn'] for 'prologue'."
},
"on_enter": {
"type": "array",
"description": "Ops run when the phase becomes active.",
"items": { "$ref": "#/$defs/op" }
},
"on_resolve": {
"type": "array",
"description": "Ops run on End Turn, before entering the next phase.",
"items": { "$ref": "#/$defs/op" }
}
}
},
"op": {
"type": "object",
"required": ["op"],
"description": "A single declarative operation. Each maps to an existing simulation primitive. The 'op' discriminator selects the variant; see each variant's required args.",
"properties": {
"op": {
"type": "string",
"enum": [
"place_spawn_box",
"roll_actor_directions",
"step_actors",
"converge_actors",
"spawn_unit",
"set_unit_actions",
"set_banner",
"lift_fog",
"emit_chronicle",
"found_city"
]
}
},
"allOf": [
{ "if": { "properties": { "op": { "const": "place_spawn_box" } } },
"then": { "required": ["actor", "count_ref", "mode_ref", "radius_ref"], "properties": {
"actor": { "type": "string", "description": "Actor tag to seed." },
"count_ref": { "type": "string", "description": "params key giving the per-mode wanderer count." },
"mode_ref": { "type": "string", "description": "params key for the start mode (tournament|custom)." },
"radius_ref": { "type": "string", "description": "params key for the spawn-box radius." } } } },
{ "if": { "properties": { "op": { "const": "roll_actor_directions" } } },
"then": { "required": ["actor", "mode_ref", "bias_ref"], "properties": {
"actor": { "type": "string" },
"mode_ref": { "type": "string", "description": "params key for the start mode (tournament|custom)." },
"bias_ref": { "type": "string", "description": "params key for the inward-bias probability." } } } },
{ "if": { "properties": { "op": { "const": "step_actors" } } },
"then": { "required": ["actor"], "properties": { "actor": { "type": "string" } } } },
{ "if": { "properties": { "op": { "const": "converge_actors" } } },
"then": { "required": ["actor", "radius_ref", "min_count_ref", "produce", "mode_ref", "cap_ref"], "properties": {
"actor": { "type": "string", "description": "Actor tag to merge." },
"radius_ref": { "type": "string", "description": "params key for the convergence radius." },
"min_count_ref": { "type": "string", "description": "params key for the minimum to form the group." },
"produce": { "type": "string", "description": "Actor tag produced by the merge (e.g. 'tribe')." },
"mode_ref": { "type": "string", "description": "params key selecting the founding-pop formula (start mode)." },
"cap_ref": { "type": "string", "description": "params key bounding the bonus founding pop." } } } },
{ "if": { "properties": { "op": { "const": "spawn_unit" } } },
"then": { "required": ["unit_id", "at"], "properties": {
"unit_id": { "type": "string" },
"at": { "description": "'centroid' | 'start' | {q,r}.", "oneOf": [ { "type": "string", "enum": ["centroid", "start"] }, { "type": "object", "additionalProperties": false, "required": ["q", "r"], "properties": { "q": { "type": "integer" }, "r": { "type": "integer" } } } ] },
"count": { "type": "integer", "minimum": 1, "default": 1 },
"controlled": { "type": "boolean", "default": false } } } },
{ "if": { "properties": { "op": { "const": "set_unit_actions" } } },
"then": { "required": ["actor", "actions"], "properties": {
"actor": { "type": "string" },
"actions": { "type": "array", "items": { "type": "string" } } } } },
{ "if": { "properties": { "op": { "const": "set_banner" } } },
"then": { "required": ["text_key"], "properties": {
"text_key": { "type": "string" },
"persist": { "type": "boolean", "default": false } } } },
{ "if": { "properties": { "op": { "const": "lift_fog" } } },
"then": { "required": ["area"], "properties": {
"area": { "type": "string", "description": "'spawn_box' or 'radius:N'." } } } },
{ "if": { "properties": { "op": { "const": "emit_chronicle" } } },
"then": { "required": ["event"], "properties": {
"event": { "type": "string", "description": "Chronicle event id." } } } },
{ "if": { "properties": { "op": { "const": "found_city" } } },
"then": { "required": ["from", "mode_ref", "cap_ref"], "properties": {
"from": { "type": "string", "description": "Actor tag to consume into the city." },
"mode_ref": { "type": "string", "description": "params key selecting the founding-pop formula (start mode)." },
"cap_ref": { "type": "string", "description": "params key bounding the bonus founding pop." } } } }
]
}
}
}