Commit Graph

7 Commits

Author SHA1 Message Date
Christopher Wiebe bf0041605f M7.1-7.2: Play-loop hand-off — Wizard → WorldGen → PlayScreen
Lands the M7 plan's first two sub-milestones on port/godot.
theriapolis-rpg-implementation-plan-godot-port-m7.md is the design
doc (six screens collapse to four scenes + a camera mode, with
per-screen behavioural contracts and a six-step sub-milestone
breakdown).

M7.1 — WorldGenProgressScreen + GameSession autoload + wizard
hand-off rewrite. GameSession holds the cross-scene state that
outlives any single screen: seed, post-worldgen Ctx, pending
character (from the M6 wizard) and pending save snapshot (for
M7.3's load path). Wizard forwards StepReview.CharacterConfirmed
upward, and TitleScreen swaps to the progress screen instead of
just printing the build summary. The progress screen runs the
23-stage pipeline on a background thread, drives a ProgressBar
from ctx.ProgressCallback, and writes the full exception trace to
user://worldgen_error.log on failure. Escape cancels at the next
stage boundary and returns to title.

M7.2 — PlayScreen with a walking character. Extracted
WorldRenderNode from the M2+M4 WorldView demo so PlayScreen and
WorldView mount the same renderer (biome image + polylines +
bridges + settlement dots + tactical chunk lifecycle + PanZoomCamera
+ per-frame layer visibility + line-width counter-scaling).
PlayScreen owns the streamer (M7.3 save needs it), composes
ContentResolver + ActorManager + WorldClock + AnchorRegistry +
PlayerController, spawns the player at the Tier-1 anchor, and
wires resident + non-resident NPC spawning from chunk-load events
with allegiance-tinted markers.

PlayerController ported engine-agnostic to Theriapolis.Godot/Input/.
Takes pre-resolved dx/dy/dt/isTactical/isFocused instead of poking
MonoGame InputManager + Camera2D, so the arithmetic that advances
PlayerActor.Position and WorldClock.InGameSeconds is bit-identical
to the MonoGame version — saves round-trip cleanly.

Click-to-travel in world-map mode (camera zoom <
TacticalRenderZoomMin), WASD step in tactical mode with axis-
separated motion + encumbrance + sub-second clock carry. HUD
overlay top-left shows HP/AC/seed/tile/biome/view-mode/time. Esc
returns to title (M7.4 replaces this with a pause menu).

Namespace gotcha: Theriapolis.GodotHost.Input shadows the engine's
Godot.Input static class for any file under the GodotHost
namespace tree. Files needing keyboard polls (WorldView,
PlayScreen) fully qualify as Godot.Input.IsKeyPressed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-10 18:07:28 -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 4d3db17a89 M6.2: Step V Abilities — drag-drop assignment + roll/auto-assign
Per GODOT_PORTING_GUIDE.md §7, the highest-risk piece in the wizard.
Three reusable widgets + the orchestrating step.

Scenes/Widgets/AbilityToken.cs:
  Draggable Control with Value + Origin metadata. _GetDragData returns
  a Dictionary payload {kind, value, from, ability, idx} per guide
  §7.1. MouseFilter = Pass so clicks propagate to the parent slot
  for the click-to-return affordance (later removed; see commit body).
  Drag preview is a dimmed duplicate.

Scenes/Widgets/AbilitySlot.cs:
  PanelContainer drop target per guide §7.2. Accepts any
  ability_value payload via _CanDropData / _DropData and emits
  Dropped(payload). Each slot owns one ability id (STR/DEX/CON/INT/
  WIS/CHA).

Scenes/Widgets/AbilityPool.cs:
  HBoxContainer drop target per guide §7.3. Accepts only slot→pool
  drops (returning an assigned value to the pool); pool→pool drops
  are no-ops.

Scenes/Steps/StepStats.cs:
  Direct port of StepStats in steps.jsx per guide §7.4. Standard
  array (default) and roll-4d6-drop-lowest method tabs; Reroll
  button visible in roll mode; Auto Assign sorts the remaining pool
  descending and places the largest values into empty slots ordered
  by class.PrimaryAbility. Three drag-drop cases (pool→slot,
  slot→slot swap, slot→pool) all delegate to a single Patch call,
  then the entire token tree rebuilds from the new draft state on
  the Changed signal — handlers don't reparent anything manually.

Issues hit during development and resolved before commit:
  - Initial click-to-return on slot pre-empted drag-from-slot every
    time (the GuiInput fired on mouse-down, before Godot detected
    the drag). Removed click-to-return — drag is the canonical
    interaction; that matches the React prototype anyway.
  - Token MouseFilter = Stop blocked clicks from reaching the slot
    layer; switched to Pass which still works as a drag source.
  - Refresh() teardown + rebuild reset the parent ScrollContainer's
    scroll to 0 every drop. CallDeferred / SetDeferred / CreateTimer
    all raced because layout settles over multiple frames; the fix
    that worked was capturing scroll position pre-rebuild and
    restoring in _Process the next frame.

Wizard.cs:
  StepTypes[5] = typeof(StepStats); the Abilities step is now
  reachable. (StepTypes[1..4, 6..7] still null — coming in M6.3+.)

Verified: all three drag scenarios + click handling + auto-assign
+ method switch + reroll work; scroll position holds across drops.

Closes M6.2. Next per guide §12: M6.3 — popover system (TraitChip +
shared PopoverLayer) before adding more easy card-grid steps.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 20:36:19 -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