Files
settled-reach/docs/sprints/sprint-16/client.md
T
jpmschweitzerandClaude Opus 4.6 bccdcfcdcb docs(docs): add frontmatter to all sprint briefings
Standardized YAML frontmatter on all 115 sprint briefing files across
sprints 1-26 with title, description, type, status, sprint number, and
team fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 00:15:45 +01:00

6.1 KiB
Raw Blame History

title, description, type, status, sprint, team
title description type status sprint team
Sprint 16 — Client Briefing Zone ID extraction optimization, sprite camera angle adjustment sprint archived 16 client

Sprint 16: Converse — Client Tasks

Goal: Dialogue becomes a two-way exchange — players pick options and the server responds; NPC information-giving deepens through trust and trait-shaped delivery; the sprite pipeline gets its correct art-direction angle; and housekeeping fixes land across all three active teams.

Branch: client Agents: Stig (dev), Tyre (arch), Hoshe (QA)

Carry-over from Sprint 15

None. Sprint 15 was 100% complete (16/16 done).

New Tickets

# Title Blocked by
#543 Optimize zone_id extraction O(N) → O(1) dictionary lookup
#540 Adjust sprite camera to D-019 angle (~15-20° from vertical) #541 (visual, must land first)

Use db/connectors/ticket show <id> for full details.

Key Decisions

  • decisions/perception.md — D-019 (top-down camera, angle amendment: ~15-20° from vertical, "the angle"), D-043 (visual style, functional warmth), D-049 (z-level rendering stack)
  • decisions/architecture.md — D-066 (dual-scale grid: 0.5m sim, 1m visual, 2x retina), D-077 (zone temperature memory, server-tracked zone_id)

Open Questions to Resolve Early

None blocking either ticket.

Notes

#543 — Optimize zone_id extraction O(N) → O(1) dictionary lookup

What exists: client/scripts/autoloads/game_state.gd apply_snapshot() function. The current zone_id extraction (lines 243-252) does a linear scan of visible_tiles on every snapshot to find the tile whose coordinates match the player position:

current_zone_id = ""
var _px := int(player_position.x)
var _py := int(player_position.y)
for _ztile in visible_tiles:
    if _ztile is Dictionary and _ztile.get("x") == _px and _ztile.get("y") == _py:
        current_zone_id = _ztile.get("zone_id", "")
        break

Within the same apply_snapshot() call (lines 256-268), visible_tiles is already iterated to build visible_positions (a Dictionary of Vector2i → true). The optimization is to build a second dictionary _tile_by_coord: Dictionary (mapping Vector2i → tile Dictionary) in that same existing loop, then replace the O(N) zone_id scan with an O(1) lookup.

What to deliver:

  1. Declare _tile_by_coord as a local variable in apply_snapshot() (or as a member var if AudioManager or others need tile data by coord)
  2. In the existing visible_tiles iteration loop (lines 256-268), add: _tile_by_coord[pos] = vtile
  3. Replace the O(N) zone_id scan (lines 243-252) with:
    var player_pos_key := Vector2i(int(player_position.x), int(player_position.y))
    var player_tile = _tile_by_coord.get(player_pos_key, null)
    current_zone_id = player_tile.get("zone_id", "") if player_tile else ""
    
  4. Remove the old loop block (lines 249-252)

Gotcha: The zone_id scan (lines 243-252) currently runs BEFORE the visible_tiles iteration that builds visible_positions (lines 256-268). You need to reorder: build _tile_by_coord in the main tile loop first, then do the zone_id lookup. The comment on line 244 ("O(1) via visible_positions dict would be ideal") confirms this was known and flagged by Tyre in a PR review — this ticket resolves it.

Net-zero complexity: The tile loop is already there. This adds one dict-set per tile in the existing loop, then removes the separate zone_id scan loop entirely. No behavioral change; the same current_zone_id value is produced.

Test: Verify current_zone_id is populated correctly after the refactor by checking the existing client P-tests or adding a unit test in gdUnit4.

#540 — Adjust sprite camera to D-019 angle (~15-20° from vertical)

Blocked by #541 (visual). Do not start until Araminta's 3D sprite render pipeline is set up and has produced at least a test sprite at the new angle.

What exists: The Godot client renders entity, object, and wall sprites. Current sprites are rendered at 90° (pure top-down). D-019 amendment specifies "the angle": Camera3D at -72.5° from horizontal (= ~17.5° from vertical, the midpoint of the 15-20° range). This matches Rimworld's orthographic-with-art-tilt approach. The Godot gameplay camera stays orthographic — the tilt is entirely an art convention baked into sprites.

What to deliver:

Once #541 delivers the offline render pipeline and a set of test sprites at -72.5°:

  1. Update client/scripts/rendering/entity_renderer.gd to reference the new sprite assets (path may change per Araminta's pipeline output structure)
  2. Verify client/scripts/rendering/tile_renderer.gd and world_renderer.gd — wall/object sprites from #541 should slot in at the same visual tile size (64×64px runtime per D-043 resolution chain)
  3. Confirm the z-sorting logic in entity_renderer.gd still produces correct results: entities south-facing should overlap objects on the same row correctly with the tilted perspective
  4. Check that the fog shader in fog_shader.gd is unaffected — fog is screen-space and driven by the LOS mask, not by sprite perspective (D-019: "tile grid remains square/orthogonal, vision cone math remains pure 2D")

Key constraint from D-066: Entity sprites render across a 2×2 sim tile footprint. With the tilt, the south-facing face of entities/objects is now visible — confirm the sprite footprint is still contained within the 2×2 sim tile bounding box so interaction range (2 sim tiles) remains accurate.

What NOT to change: The client/scripts/rendering/fog_shader.gd, fog vision cone shape, or any LOS computation. Those are 2D sim-space and are unaffected by the art-direction angle.

Dependency Chain

#543 (zone_id O(1)) → standalone, no dependencies

#541 (visual: 3D render pipeline) → #540 (sprite camera angle)

PR Workflow

When ready to submit, create a PR with tea CLI. All flags are required to avoid TTY prompts (see CLAUDE.md "Gitea access" section):

tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(client): sprint 16 zone lookup + sprite angle" --description "body" --base main --head client