Add structure dots toggle to graphics settings (#4356)

## What

Adds an on/off **Structure dots** toggle to the graphics settings modal
(Structure Icons section), controlling whether structures collapse into
small dots when zoomed out.

## How

The renderer already gates the dots LOD on `structure.dotsZoomThreshold`
(structures become dots when `zoom <= threshold`). The debug GUI exposes
that threshold as a slider; this surfaces a simple player-facing toggle:

- `GraphicsOverrides.ts` — adds `structure.showDots` (boolean) to the
override schema.
- `RenderOverrides.ts` — when `showDots === false`,
`applyGraphicsOverrides` sets `dotsZoomThreshold = 0`. Since zoom is
always > 0, the dots LOD never triggers, so structures keep their full
icon at every zoom. When enabled (default), the threshold is left
untouched.
- `GraphicsSettingsModal.ts` — toggle button mirroring the existing
Classic icons / Classic level numbers toggles; defaults to On.
- `en.json` — `structure_dots_label` / `structure_dots_desc`.

The change applies live: a `settings.graphics` change re-runs
`applyGraphicsOverrides` onto the live settings object the passes read
each frame, and `dotsZoomThreshold` is a per-frame uniform.

## Testing

- `tsc --noEmit` clean.
- Verified in a headless solo game: the toggle renders (default On),
flipping it persists `structure.showDots = false`, and
`applyGraphicsOverrides` yields `dotsZoomThreshold` 1.2 when on / 0 when
off.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Evan
2026-06-22 12:58:30 -07:00
committed by evanpelle
parent 55916b807b
commit 6afa3e48f5
4 changed files with 38 additions and 0 deletions
+2
View File
@@ -564,6 +564,8 @@
"section_name_labels": "Name Labels",
"section_structure_icons": "Structure Icons",
"section_terrain": "Terrain",
"structure_dots_desc": "Collapse structure icons into small dots when zoomed out",
"structure_dots_label": "Structure dots",
"territory_alpha_desc": "How opaque the territory fill is (lower lets terrain show through)",
"territory_alpha_label": "Territory opacity",
"territory_sat_desc": "How vivid the territory fill colors are (lower mutes them)",
@@ -485,6 +485,14 @@ export class GraphicsSettingsModal extends LitElement implements Controller {
this.patchStructure({ classicNumbers: !this.currentClassicNumbers() });
}
private currentShowDots(): boolean {
return this.userSettings.graphicsOverrides().structure?.showDots ?? true;
}
private onToggleShowDots() {
this.patchStructure({ showDots: !this.currentShowDots() });
}
private patchPassEnabled(patch: Partial<GraphicsOverrides["passEnabled"]>) {
const current = this.userSettings.graphicsOverrides();
this.userSettings.setGraphicsOverrides({
@@ -593,6 +601,7 @@ export class GraphicsSettingsModal extends LitElement implements Controller {
const iconSize = this.currentIconSize();
const classicIcons = this.currentClassicIcons();
const classicNumbers = this.currentClassicNumbers();
const showDots = this.currentShowDots();
const highlightFill = this.currentHighlightFill();
const highlightBrighten = this.currentHighlightBrighten();
const highlightThicken = this.currentHighlightThicken();
@@ -911,6 +920,25 @@ export class GraphicsSettingsModal extends LitElement implements Controller {
</div>
</button>
<button
class="flex gap-3 items-center w-full text-left p-3 hover:bg-slate-700 rounded-sm text-white transition-colors"
@click=${this.onToggleShowDots}
>
<div class="flex-1">
<div class="font-medium">
${translateText("graphics_setting.structure_dots_label")}
</div>
<div class="text-sm text-slate-400">
${translateText("graphics_setting.structure_dots_desc")}
</div>
</div>
<div class="text-sm text-slate-400">
${showDots
? translateText("user_setting.on")
: translateText("user_setting.off")}
</div>
</button>
<div
class="px-3 py-1 text-xs font-semibold text-slate-400 uppercase tracking-wider mt-2"
>
@@ -17,6 +17,9 @@ export const GraphicsOverridesSchema = z
iconSize: z.number(),
classicIcons: z.boolean(),
classicNumbers: z.boolean(),
// When false, structures keep their full icon at any zoom instead of
// collapsing to dots when zoomed out (forces dotsZoomThreshold to 0).
showDots: z.boolean(),
})
.partial(),
mapOverlay: z
+5
View File
@@ -42,6 +42,11 @@ export function applyGraphicsOverrides(
if (overrides.structure?.classicNumbers !== undefined) {
settings.structureLevel.classicFont = overrides.structure.classicNumbers;
}
if (overrides.structure?.showDots === false) {
// Zoom is always > 0, so a threshold of 0 means the dots LOD never
// triggers — structures stay as full icons at every zoom level.
settings.structure.dotsZoomThreshold = 0;
}
if (overrides.mapOverlay?.highlightFillBrighten !== undefined) {
settings.mapOverlay.highlightFillBrighten =
overrides.mapOverlay.highlightFillBrighten;