b1fc3f244ba9d5a9111f6e1d13a0f187ce2eba9e
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b1fc3f244b |
M7.4b: Top-right cursor-debug panel for play-testing
Mirror of the player-status panel, anchored top-right. Per-frame
sample of GetViewport().GetMousePosition() converted to world coords
via the camera transform; surfaces:
- World-pixel and world-tile coords under the cursor
- Biome at that tile
- Feature flag bitmask (HasRoad / HasRiver / HasRail / IsSettlement
/ IsPoi / IsCoast / RiverAdjacent / RailroadAdjacent)
- Settlement on the tile via WorldTile.SettlementId lookup —
name, tier, and economy/governance/pop (or PoI type)
- Bridge under cursor via point-on-segment hit test against
world.Bridges (6 px hit radius, ≤ a few dozen bridges so cheap)
- Tactical block when zoomed in: tactical-tile coords, surface +
variant, deco, walkability tag (walkable / slow / blocked)
- NPC under cursor within 12 px hit radius — display name, role
tag or template id, allegiance, HP
Cached StringBuilder field on PlayScreen (Clear() each frame instead
of new'ing) to keep per-frame GC pressure low. Held keys produce
auto-repeat InputEventKey instances that Godot 4 mono's GC must
collect before engine shutdown; reducing per-frame garbage buys
that collection more headroom and avoided a shutdown-assertion
race observed on the first launch with the panel mounted.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
6f47700820 |
M7.4a: PlayScreen polish — facing tick, road overlap, WASD pan
Facing tick stuck at the initial angle. PlayerMarker._Draw was computing the tick direction from a FacingAngleRad auto-property, but Godot caches CanvasItem draw commands and only re-runs _Draw on QueueRedraw. Setter never called QueueRedraw → tick never rotated. Fixed by leaning on the Node2D transform instead: tick is drawn along the local +X axis, PlayScreen sets marker.Rotation = facing each frame. The transform rotation applies to the cached commands without re-invoking _Draw — efficient and correct. FacingAngleRad property removed; ShowFacingTick became a property with QueueRedraw on change (visibility toggle still needs to invalidate the cache). Tactical view double-drew roads. TacticalChunkGen.Pass2_Polylines already bakes roads + rivers + bridges into the surface tiles of each chunk. WorldRenderNode's Line2D overlay was still visible at tactical zoom, stroking the same path on top of the rasterised version — showed as a brown line over every road. Ported the MonoGame "suppress polyline overlay in tactical" rule into UpdateLayerVisibility: _polylineLayer and _bridgeLayer hide when zoom >= TacticalRenderZoomMin. WASD now pans the world map. Previously WASD did nothing in world-map mode — only right-drag / middle-drag / mouse-wheel worked. WASD is now context-sensitive: tactical mode steps the player (unchanged), world-map mode pans the camera at 400 screen px/sec (world-pixel speed scales as 1/zoom so the perceived rate stays constant). Diagonal motion is √2-normalised to match tactical step. Suppressed during click-to-travel since the camera-follow would clobber any pan input anyway. HUD hint updated. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
116193c1e3 |
M7.4: Pause menu + save-from-pause, slot rows show wall-clock time
PauseMenuScreen — CanvasLayer overlay on PlayScreen, Layer=50 with ProcessMode=WhenPaused so it stays responsive while the tree is paused. _Ready sets GetTree().Paused=true; Resume/Close/QuitToTitle unpause first. Two sub-states share one VBoxContainer-and-status-label panel: main menu (Resume / ★ Level Up / Save Game / Quicksave / Quit to Title) and slot picker. Save Game flips to the picker, click a slot to write, back returns to main. Esc backs out of picker to main on first press, closes the overlay on a second. CodexTheme applied at the panel root since overlays mount outside PlayScreen's Control tree and theme cascade doesn't cross CanvasLayer boundaries. Level-up button surfaces only when LevelUpFlow.CanLevelUp(pc) returns true (matches MonoGame), and is rendered disabled with a "ships with M8" tooltip — fresh L1 characters won't see it in M7 play-tests. Quit to Title autosaves first (matches MonoGame). A failed autosave doesn't block the quit; better to let the user leave than trap them. Save-from-pause writes to an internal status label inside the panel rather than PlayScreen's save-flash toast — the toast lives on the paused tree branch and would freeze mid-fade. PlayScreen Esc now AddChild(new PauseMenuScreen(this)) instead of BackToTitle. Added paused-guard + Echo filter in _Input. New public PlayerCharacter() accessor lets the pause panel call CanLevelUp. HUD hint updated to "F5 quicksaves · Esc opens pause". SaveSlotFormat — shared helper between SaveLoadScreen (load picker) and PauseMenuScreen (save picker) so both surfaces render rows with the same prefix + in-game time + wall-clock time. Parses SavedAtUtc, converts to local time, renders relative (today/yesterday), short (MMM d, HH:mm within year), or full (yyyy-MM-dd HH:mm), with "<unknown>" fallback for empty headers. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
8e2efdd878 |
M7.3: Save/load round-trip — F5 quicksave, Continue → slot picker
SavePaths ported verbatim from Theriapolis.Game/Platform/. Same OS directories as MonoGame (%LOCALAPPDATA%\Theriapolis\Saves on Windows, ~/Library/Application Support/Theriapolis/Saves on macOS, $XDG_DATA_HOME/Theriapolis/saves on Linux) so saves round-trip across the two builds without migration. PlayScreen save layer. Wired PlayerReputation + Flags + QuestEngine + QuestContext + _killedByChunk + _pendingEncounterRestore in _Ready, even though M7.3 doesn't actively drive any of those — they're round-trip-required, so a save written by the MonoGame build with non-empty rep/flags/quest state loads here and re-saves without data loss. SaveTo/BuildHeader/CaptureBody/ApplyRestoredBody are field-for-field ports of the MonoGame methods (Phase 5 M3 + M5, Phase 6 M2 + M4); CaptureBody flushes the streamer first so chunk deltas land in the store before serialisation. HandleChunkLoaded now honours _killedByChunk so a killed spawn stays dead across chunk reload + save round-trip. F5 quicksaves to the autosave slot. Save-flash toast (bottom-center Label, fade-out via Modulate.A) confirms each write. _Ready branches on session.PendingRestore: when set (load path), calls ApplyRestoredBody and skips the new-game spawn; otherwise spawns at the Tier-1 anchor with the M6 character. The mid-combat encounter snapshot is captured on save but the push to CombatHUDScreen is the M8 stub (logs a console diagnostic). SaveLoadScreen — load-only slot picker. Header-only deserialise per row (SaveCodec.DeserializeHeaderOnly reads just the JSON prefix, body untouched), so opening the picker is cheap even with many large saves. Slot label matches MonoGame's SlotLabel() format exactly. Incompatible / unreadable rows render disabled with the reason inline. TitleScreen Continue. Enable-gate replaced — was "user://character.json exists" (M7.1 placeholder), now scans SavesDir for *.trps + checks SaveCodec.IsCompatible. OnContinue swaps to SaveLoadScreen instead of the print stub. Manual play-test loop confirmed: F5 in run #1, quit, relaunch, Continue → Autosave row → progress bar → PlayScreen with character restored at saved tile. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
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> |