Commit Graph

7 Commits

Author SHA1 Message Date
Christopher Wiebe e1fb988969 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>
2026-05-04 21:03:56 -07:00
Christopher Wiebe 8bf9eba2a7 M6.8: Hybrid trait pickers (Phase B)
Per theriapolis-rpg-clades.md "Building a Hybrid": hybrids now pick
two clade traits from the dominant parent + one from the other (2/1
split keyed off DominantParent), and one species trait + one species
detriment from each parent. All clade detriments still inherit fully
from both parents. Universal hybrid detriments unchanged.

CharacterDraft gains six new fields (sire/dam clade-trait arrays,
sire/dam species trait/detriment ids) and a CladeTraitLimit(lineage)
helper. Step 0/1 validators enforce the picks; Aside renders only the
chosen subset for hybrids.

Cascading clears: clade swap clears that lineage's bonus + clade
traits + (if species also invalidated) species pick; species swap
clears that lineage's species trait/detriment; dominant flip trims
overflow from the end (non-destructive when possible); hybrid-off
clears all six new fields.

Toggle buttons in both steps wire MouseEntered/Exited into
PopoverLayer so the player can read each trait's description on
hover (detriment buttons get the red-tinted "DETRIMENT" popover).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 20:12:56 -07:00
Christopher Wiebe e3f0296e6f M6.7: Parchment theme pass
Lights up the M5 codex design system across the wizard. Default
palette swaps from dark leather to aged-parchment cream with
sealing-wax red selection emphasis, matching the React prototype's
default theme variant. CodexTheme.Build() is applied at the wizard
root so every step + Aside + popover cascades through it.

Theme additions:
- Parchment palette in CodexPalette (Dark retained as alt)
- Type variations registered for Card, CodexPopover, Pill,
  PillDetriment, AbilityToken, AbilitySlot, SkillRow — without
  SetTypeVariation, panel-stylebox lookup falls through to Godot's
  default dark slate, which is what was happening to every bare
  PanelContainer before this pass.
- panel_hover stylebox on Card (gild border) wired via CodexCard's
  MouseEntered/Exited helper; panel_selected bumped to 3px seal-red
  border + soft shadow so selection reads at a glance.

Card selection refactor:
- Replaced the warm-cream Modulate hint on cards with stylebox swaps
  via the new CodexCard.SetSelected helper. The Modulate approach
  was a no-op on cream-on-cream parchment; the stylebox swap looks
  the same on either palette.
- Step intros + Aside section headers now use the existing Eyebrow /
  H2 / H3 / CardName / CardMeta / CardBody label variations.
- Confirm button on Step VIII uses the PrimaryButton variation.

Popover + chip behaviour:
- PopoverLayer is now MouseFilter=Ignore so clicks/scroll/hover all
  pass through. Adjacent chips fire reliably even when the previous
  popover overlaps them spatially.
- Dropped the 80ms grace timer; chip MouseExited closes immediately.
- TraitChip MouseFilter Stop → Pass so clicks bubble up to the
  parent card's GuiInput (selecting the card).

Misc:
- Wizard._Ready inserts a backing Panel so the parchment Bg fills
  the canvas — Wizard root is a plain Control, which paints nothing.
- CodexTheme font lookup tries Cormorant-Medium before -Regular and
  globalizes res://Fonts/ for runtime FontFile load (the previous
  fallback used ContentPaths which points at a sibling data tree).
- StepStats final-score Label rendered at font_size 22 to match the
  AbilityToken die.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-03 22:04:24 -07:00
Christopher Wiebe bb986d49f9 M6.6: StepReview signing + hybrid math revision
- New Step VIII (Review): name input and Confirm button that
  saves the finalized character to user://character.tres.
- Hybrid lineage rules simplified per project decision: drop
  the "no-stack on overlap, take +1 free elsewhere" rule from
  theriapolis-rpg-clades.md. Hybrids now pick one ability mod
  from each parent clade and they sum if they overlap.
  Removes HybridFreeAbility, the free-bonus picker row, and the
  overlap special case from AbilityCalc + WizardValidation.
- StepClade bonus rows now mutate in place (sync ButtonPressed)
  instead of tearing down on every Refresh — the old path freed
  the very button mid-Pressed-signal, leaving stale buttons next
  to the new ones.
- StepSkills drops the redundant "Calling: X · History: Y" meta
  line; both are already shown in the Aside summary.
- Aside hybrid section adds dual-species traits and the
  universal-hybrid detriment pills.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-03 20:51:55 -07:00
Christopher Wiebe 0e5d4b7425 M6.5: StepSkills + ability-bonus breakdown + Aside redesign
The skills step lands as the last data-driven character creation step
(only Sign — name + confirm — remains for M6.6). Brought a few cross-
cutting refactors with it.

Scenes/Steps/StepSkills.cs:
  Direct port of StepSkills in src/steps.jsx — all 18 skills laid out
  in 6 ability-grouped panels (STR/DEX/CON/INT/WIS/CHA), 2-column
  grid. Background-granted skills appear pre-checked and locked;
  user picks `class.SkillsChoose` more from `class.SkillOptions`.
  Hover the skill name → popover with the codex flavor description
  (limited to the title only — hovering checkboxes / source tags
  doesn't trigger the popover, avoids interference with adjacent
  rows' click targets). Fixed-width [✓] / [ ] / [—] checkbox slot
  so toggling doesn't shift the row layout.

UI/SkillsCatalog.cs (new):
  Static skill table — JSON id, display label, governing ability,
  and the codex SKILL_DESC text ported verbatim from src/data.jsx.
  Mirrors Theriapolis.Core.Rules.Stats.SkillId; descriptions live
  here because backgrounds.json and classes.json don't carry them.

UI/AbilityCalc.cs (new):
  Final-score math — base assignment + clade and species mods, with
  per-source breakdown for the bonus popover ("+1 from Canidae · +2
  from Wolf"). Hybrid mode tags each clade source with its lineage
  ("(sire)" / "(dam)"). Used by both StepStats and the Aside so the
  two views can never disagree on what a +N badge means.

UI/BackgroundAvailability.cs (new):
  Extracted from StepBackground — shared rules table for hybrid-only
  and clade-restricted backgrounds. Now also consulted by StepClade
  when the player changes lineage: the currently-selected background
  is auto-cleared if the new lineage no longer satisfies its rule
  (e.g., Pack-Raised clears when switching from Canidae to Felidae,
  Passer clears when toggling Hybrid off). Implemented via
  Resource.Duplicate + Patch on the duplicate to evaluate the
  hypothetical post-patch state without committing prematurely.

StepStats.cs:
  Per-row layout extended: ability label | slot | bonus chip | final
  | d20 mod. Bonus chip is a TraitChip with the per-source breakdown
  in its hover description. Auto-assign now sorts empty abilities by
  AbilityCalc.TotalBonus DESCENDING (with class.PrimaryAbility as
  tiebreaker) — biggest pool value lands on the ability already
  receiving the biggest lineage bonus, maximising final scores.

Aside.cs (significant redesign):
  - Name centered at top.
  - Lineage details: 2-column grid, full-width.
    - Purebred:  Clade | Species, then Calling | Background, then
                 Subclass | (empty).
    - Hybrid:    SIRE ★ | DAM (centered + underlined column heads),
                 Clade | Clade, Species | Species, then the same
                 calling/background/subclass rows.
  - Attributes: STR/DEX/CON/INT/WIS/CHA each with bonus chip (omitted
    when +0), final score, d20 modifier. Self-contained min-width
    table so it can't widen the panel beyond its alloc.
  - Pills: traits, detriments, level-1 features, background feature,
    skill chips (BG-locked + user-chosen). All hoverable for descriptions.
  - Whole panel wraps in a ScrollContainer so an over-tall summary
    scrolls in place instead of pushing the wizard layout off-screen.
  - Width nudged 320 → 360px. Smaller font on label tags, autowrap
    on value labels so long names ("Hybrid Underground") wrap rather
    than push the panel wider.

Card grids: changed all five card-grid steps (Clade, Species, Class,
Subclass, Background) from SizeFlagsHorizontal.ExpandFill →
ShrinkCenter. Cards stay at their CustomMinimumSize 200 wide and
the grid horizontally centers in PageMain. The right-side gap
between content and Aside is now uniform regardless of how many
cards or whether the last row is partial — fixes the "Clade tab
feels too padded, Background tab too tight" perception.

Closes M6.5. Per guide §12, what's left in M6: M6.6 (StepReview —
name + summary + Confirm handoff per guide §11) and M6.7 (parchment
Theme pass).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-03 18:10:05 -07:00
Christopher Wiebe ce87eb11ad M6.4: Card-grid steps + hybrid origin + clade-restricted backgrounds
Per GODOT_PORTING_GUIDE.md §12, the four "easy" card-grid steps land
together (Species / Calling / Subclass / History), plus three real
features that emerged during testing: cross-step validation gating,
hybrid origin, and clade-restricted background availability.

New step files (Scenes/Steps/):
  StepSpecies.cs    — cards filtered by clade; for hybrids shows two
                      stacked grids (Sire / Dam).
  StepClass.cs      — all classes; class change clears chosen skills
                      and the previously-selected subclass.
  StepSubclass.cs   — subclasses filtered by ClassDef.SubclassIds.
  StepBackground.cs — backgrounds filtered by hybrid + clade rules
                      (see below).

UI/WizardValidation.cs (new):
  Static per-step validators against CharacterDraft. Replaces the
  per-instance Validate() route on the wizard side — Wizard now
  computes the lock state for every step in the flow, not just the
  current one. Mirrors app.jsx's firstIncomplete rule exactly.

  Bug it fixes: previously the wizard checked only the current step's
  validity, so picking a clade let you skip directly to Abilities
  without picking species/calling/etc.

UI/CharacterDraft.cs:
  Phase 6.5 hybrid fields — IsHybrid, SireCladeId, SireSpeciesId,
  DamCladeId, DamSpeciesId, DominantParent. EffectiveCladeId /
  EffectiveSpeciesId resolve to the dominant parent's lineage when
  hybrid; downstream steps don't need to care which path. Helpers
  HasClade(id) and HasAnyCladeOfKind(kind) feed the background
  availability rules.

StepClade.cs:
  Hybrid toggle splits the picker into Sire + Dam grids with a
  Dominant Lineage radio. Validation refuses same-clade Sire+Dam.
  Switched to build-once + mutate-in-place: cards are created once
  during Build(), Refresh just updates Modulate per selection state.
  Tearing down + rebuilding inside the click callback caused
  duplicates because Free() defers when the freed node is mid-signal.

StepBackground.cs:
  Availability rules table — predicates per restricted background id.
  Hybrid-only: passer, hybrid_underground, former_chattel.
  Clade-restricted: warren_runner (Leporidae), pack_raised (Canidae),
  herd_city_born (any prey clade).
  Hybrids match if either parent satisfies the rule.

Other steps (Species/Class/Subclass/Background):
  Refresh dispatched via Callable.From(Refresh).CallDeferred() so the
  rebuild runs after the click handler completes — same Free()-during-
  signal bug as StepClade hit, fixed via deferral instead of mutate-
  in-place because the card lists are dynamic (clade- / class- /
  hybrid-flag-dependent).

Wizard.cs:
  - RebuildStepperStates uses WizardValidation.FirstIncomplete to lock
    every step past the first unsatisfied one.
  - OnStepperClicked checks every step in [0..target-1].
  - UpdateChrome's banner uses WizardValidation for the active step.
  - Scroll preservation moved here (snapshot before step.Refresh
    fires, restore in _Process); StepStats's local copy removed.

Wizard.tscn:
  Scroll node marked unique_name_in_owner so Wizard can grab it.
  PopoverLayer's TraitChip is reused throughout the new step cards.

Aside.cs:
  Hybrid-aware summary — shows "Sire (dominant)" / "Dam" lineage rows
  when IsHybrid; otherwise the existing Clade / Species rows.

Verified end-to-end:
  - Walk Clade → Species → Calling → Subclass → History → Abilities
  - Stepper locks every step past first unsatisfied
  - Hybrid toggle works both directions, dominant changes lineage
  - Hybrid-only and clade-restricted backgrounds appear / disappear
    based on lineage
  - Scroll position preserved across selections
  - Drag-drop still works on Abilities

Closes M6.4. Per guide §12, next is M6.5 — StepSkills (class-driven
choice list with TraitChip per skill).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 22:24:33 -07:00
Christopher Wiebe ee5439285c M6.1: Character creation wizard foundation (.tscn + Resource-based draft)
Pivots from M5's code-built UI to the editor-authorable .tscn pattern
recommended in GODOT_PORTING_GUIDE.md, after a session of fighting
Godot idioms with code-only layout. Default theme only; the parchment
Theme lands last per the guide's §12 build order so layout bugs surface
as layout bugs, not theming bugs.

GODOT_PORTING_GUIDE.md:
  Authored by Claude Design as the canonical port reference. Maps the
  React prototype's structure onto Godot 4.6 with concrete code sketches
  and a build-order recommendation. Drove the M6 architecture.

Fonts/:
  Cormorant Garamond (Medium + MediumItalic) and Crimson Pro (Regular +
  Italic + SemiBold) under OFL — the React prototype's serif-display
  and serif-body families. Not yet wired through CodexTheme.Build()
  because theming is deferred; CodexTheme.LoadFontFromFonts already
  picks them up automatically when the Theme pass lands.

Scenes/Wizard.tscn + Wizard.cs:
  Wizard shell per guide §4: codex-header (title + folio counter) +
  Stepper + Page (StepHost + Aside) + NavBar (Back / validation / Next).
  All node lookups via unique-name (%) syntax; layout authored as a
  scene file you can open in the editor. Step lifecycle drives the
  Aside via signal binding. Stepper logic mirrors app.jsx — locked
  iff some EARLIER step is unsatisfied; "type not yet implemented"
  doesn't lock.

Scenes/Aside.tscn + Aside.cs:
  Right-rail summary per guide §10. Single Refresh() rebuild on
  CharacterDraft.Changed; cheap enough not to bother with partial
  updates. Width 320 (was 380 before the layout overflow fix).

Scenes/Steps/IStep.cs + StepClade.cs:
  Per-step Bind(draft) + Validate() contract. StepClade renders the
  3-column clade card grid; click commits via CharacterDraft.Patch
  which triggers the Resource.Changed signal that Aside and Wizard
  both subscribe to.

UI/CharacterDraft.cs:
  Resource (not Node) per guide §2.1. Mirrors app.jsx's `state` shape
  exactly. Patch(dictionary) emits the inherited Resource.Changed
  signal — listeners use `draft.Changed += handler` regardless of
  which field changed. CodexContent provides lazy-loaded immutable
  content tables (Clades, Species, Classes, Subclasses, Backgrounds).

Main.{cs,tscn}: Node → Control
  When Main was a Node, Control children couldn't anchor to a real
  parent rect — they sat at (0,0) at intrinsic min size. With wide
  step content (3-column 200-px-card grid), the Wizard's min size
  pushed the navbar beyond the viewport's right edge, hiding the Next
  button on smaller windowed viewports. Making Main a full-rect-
  anchored Control gives child scenes a proper rect to lay out in.

UI/Widgets/CodexStepper.cs:
  Anchored the inner vbox to fill the button rect. Without this, the
  vbox sat at the button's top-left at intrinsic size and labels
  rendered in the corner — visible as the active-step label being
  off-center from the highlight bar.

Verified at 1152x720 windowed and (separately) at fullscreen:
  - 3-column card grid fits inside Wrap margins + Aside without
    horizontal overflow
  - Stepper labels centered under their highlight bars
  - Next button visible after clade selection; future steps switch
    to "coming soon" placeholder when clicked
  - Aside summary fills in CLADE block on selection

Closes M6.1.  Next per guide §12 build order: M6.2 — StepStats with
drag-drop (highest-risk piece, de-risk before easy steps).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 19:35:03 -07:00