M6.13: Sex picker + species variant schema
Adds character Sex (male/female) as a top-level CharacterDraft field
required for every character, and species variants as a layer on top
of the base species record. Two variant axes:
- "sex": auto-resolves from CharacterDraft.Sex for purebreds; for
hybrids, pinned by parent role (sire = male, dam = female)
by definition. No picker needed beyond Step 0.
- "lineage": explicit per-species pick (Ram-Folk's sheep/goat). Has
its own picker on Step 1 (purebred path under the grid;
hybrid path embedded into the per-parent pick column).
Schema (Theriapolis.Core/Data):
- SpeciesDef gains VariantAxis (string) and Variants (array of
SpeciesVariantDef { Id, Name, Traits, Detriments }).
- JSON content not yet populated — that's M6.14.
CharacterDraft adds:
- Sex (required by Step 0 validation)
- SpeciesVariant / SireSpeciesVariant / DamSpeciesVariant
- ResolveVariantId(species, role) that returns the active variant
id for a given context — used by Aside to layer variant traits
onto the base species traits.
Step 0 (StepClade): sex picker row above the hybrid toggle. Two
toggle buttons radio-style.
Step 1 (StepSpecies): purebred path renders a lineage picker below
the grid when the picked species has VariantAxis == "lineage";
hybrid path embeds a lineage picker at the top of each parent's
pick column. Hover popovers summarise each variant's contents.
Validation: Sex is required at Step 0. Lineage variant required at
Step 1 for any picked species (purebred or per-hybrid-parent) with
VariantAxis == "lineage".
Aside: AddVariantContent layers the resolved variant's extra
traits/detriments onto the base species rendering, for both purebred
and hybrid paths.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,8 @@ public partial class StepClade : VBoxContainer, IStep
|
||||
{
|
||||
private CharacterDraft _draft = null!;
|
||||
private Button _hybridToggle = null!;
|
||||
private Button _sexMaleBtn = null!;
|
||||
private Button _sexFemaleBtn = null!;
|
||||
private VBoxContainer _purebredSection = null!;
|
||||
private VBoxContainer _hybridSection = null!;
|
||||
private OptionButton _dominantToggle = null!;
|
||||
@@ -83,6 +85,27 @@ public partial class StepClade : VBoxContainer, IStep
|
||||
AutowrapMode = TextServer.AutowrapMode.WordSmart,
|
||||
});
|
||||
|
||||
// Sex picker — required for every character. For purebreds with
|
||||
// sex-axis variants (Elk, Lion) this drives variant resolution;
|
||||
// for hybrids it's identity-only since sire/dam are male/female
|
||||
// by parent-role definition.
|
||||
var sexRow = new HBoxContainer();
|
||||
sexRow.AddThemeConstantOverride("separation", 8);
|
||||
AddChild(sexRow);
|
||||
sexRow.AddChild(new Label { Text = "SEX", ThemeTypeVariation = "Eyebrow" });
|
||||
_sexMaleBtn = new Button
|
||||
{
|
||||
Text = "Male", ToggleMode = true, FocusMode = Control.FocusModeEnum.None,
|
||||
};
|
||||
_sexFemaleBtn = new Button
|
||||
{
|
||||
Text = "Female", ToggleMode = true, FocusMode = Control.FocusModeEnum.None,
|
||||
};
|
||||
_sexMaleBtn.Pressed += () => OnSexPicked("male");
|
||||
_sexFemaleBtn.Pressed += () => OnSexPicked("female");
|
||||
sexRow.AddChild(_sexMaleBtn);
|
||||
sexRow.AddChild(_sexFemaleBtn);
|
||||
|
||||
// Toggle Button (not CheckBox) so the inverted-on-press button style
|
||||
// from the codex theme handles selection visually — no checkbox glyph
|
||||
// needed, the bg colour shift is the affordance.
|
||||
@@ -224,6 +247,9 @@ public partial class StepClade : VBoxContainer, IStep
|
||||
_draft.Patch(patch);
|
||||
}
|
||||
|
||||
private void OnSexPicked(string sex) =>
|
||||
_draft.Patch(new Godot.Collections.Dictionary { { "sex", sex } });
|
||||
|
||||
private void OnDominantSelected(long index)
|
||||
{
|
||||
string newDominant = index == 0 ? "sire" : "dam";
|
||||
@@ -259,6 +285,11 @@ public partial class StepClade : VBoxContainer, IStep
|
||||
_purebredSection.Visible = !hybrid;
|
||||
_hybridSection.Visible = hybrid;
|
||||
|
||||
bool isMale = _draft.Sex == "male";
|
||||
bool isFemale = _draft.Sex == "female";
|
||||
if (_sexMaleBtn.ButtonPressed != isMale) _sexMaleBtn.SetPressedNoSignal(isMale);
|
||||
if (_sexFemaleBtn.ButtonPressed != isFemale) _sexFemaleBtn.SetPressedNoSignal(isFemale);
|
||||
|
||||
UpdateSelection(_purebredCards, _draft.CladeId);
|
||||
UpdateSelection(_sireCards, _draft.SireCladeId);
|
||||
UpdateSelection(_damCards, _draft.DamCladeId);
|
||||
|
||||
Reference in New Issue
Block a user