diff --git a/resources/lang/en.json b/resources/lang/en.json index 8b62a1fb2..7ba5c4f78 100644 --- a/resources/lang/en.json +++ b/resources/lang/en.json @@ -547,6 +547,8 @@ "name_cull_desc": "Hide names smaller than this size", "name_cull_label": "Minimum name size", "name_scale_label": "Name Scale", + "nuke_color_desc": "Color of the fallout tint left on territory after a nuke.", + "nuke_color_label": "Nuke fallout color", "ocean_color_desc": "Base color of ocean.", "ocean_color_label": "Ocean color", "rail_distance_desc": "How far zoomed out train tracks remain visible", diff --git a/src/client/hud/layers/GraphicsSettingsModal.ts b/src/client/hud/layers/GraphicsSettingsModal.ts index d0b65abac..bf423453d 100644 --- a/src/client/hud/layers/GraphicsSettingsModal.ts +++ b/src/client/hud/layers/GraphicsSettingsModal.ts @@ -115,6 +115,22 @@ function falloffToUnitGlowSlider(falloff: number): number { const HEX_COLOR_RE = /^#?([0-9a-fA-F]{6})$/; +// The stale-nuke (fallout ground tint) color is stored in render-settings.json +// as three 0-1 floats; the color picker wants a "#rrggbb" hex string. +function rgbFloatsToHex(r: number, g: number, b: number): string { + const ch = (v: number) => + Math.round(v * 255) + .toString(16) + .padStart(2, "0"); + return `#${ch(r)}${ch(g)}${ch(b)}`; +} + +const NUKE_COLOR_DEFAULT = rgbFloatsToHex( + renderDefaults.mapOverlay.staleNukeR, + renderDefaults.mapOverlay.staleNukeG, + renderDefaults.mapOverlay.staleNukeB, +); + export class ShowGraphicsSettingsModalEvent { constructor( public readonly isVisible: boolean = true, @@ -356,6 +372,20 @@ export class GraphicsSettingsModal extends LitElement implements Controller { this.patchMapOverlay({ coordinateGridOpacity: value }); } + private currentNukeColor(): string { + return ( + this.userSettings.graphicsOverrides().mapOverlay?.staleNukeColor ?? + NUKE_COLOR_DEFAULT + ); + } + + private onNukeColorChange(event: Event) { + const value = (event.target as HTMLInputElement).value.trim(); + const match = HEX_COLOR_RE.exec(value); + if (!match) return; // ignore partial/invalid hex while typing + this.patchMapOverlay({ staleNukeColor: `#${match[1].toLowerCase()}` }); + } + private onRailDrawDistanceChange(event: Event) { const drawDistance = parseFloat((event.target as HTMLInputElement).value); // Invert: higher draw distance => tracks visible when more zoomed out. @@ -572,6 +602,7 @@ export class GraphicsSettingsModal extends LitElement implements Controller { const railDrawDistance = RAIL_ZOOM_MAX - this.currentRailMinZoom(); const railThickness = this.currentRailThickness(); const oceanColor = this.currentOceanColor(); + const nukeColor = this.currentNukeColor(); const ambientLevel = this.currentAmbientLevel(); const unitGlow = this.currentUnitGlow(); const colorblind = this.currentColorblind(); @@ -1123,6 +1154,33 @@ export class GraphicsSettingsModal extends LitElement implements Controller { /> +
+
+
+ ${translateText("graphics_setting.nuke_color_label")} +
+
+ ${translateText("graphics_setting.nuke_color_desc")} +
+
+ + +
+
diff --git a/src/client/render/gl/GraphicsOverrides.ts b/src/client/render/gl/GraphicsOverrides.ts index 021450c6a..b697e2d24 100644 --- a/src/client/render/gl/GraphicsOverrides.ts +++ b/src/client/render/gl/GraphicsOverrides.ts @@ -27,6 +27,9 @@ export const GraphicsOverridesSchema = z territorySaturation: z.number(), territoryAlpha: z.number(), coordinateGridOpacity: z.number(), + // "#rrggbb" hex string; overrides the lingering fallout ground tint + // left on territory after a nuke. + staleNukeColor: z.string(), }) .partial(), railroad: z diff --git a/src/client/render/gl/RenderOverrides.ts b/src/client/render/gl/RenderOverrides.ts index 5d53883e5..001c9ca7d 100644 --- a/src/client/render/gl/RenderOverrides.ts +++ b/src/client/render/gl/RenderOverrides.ts @@ -1,5 +1,6 @@ import type { GraphicsOverrides } from "./GraphicsOverrides"; import { createThemeSettings, type RenderSettings } from "./RenderSettings"; +import { hexToRgb } from "./utils/ColorUtils"; /** * Apply the user's graphics overrides onto a RenderSettings in place: name @@ -64,6 +65,15 @@ export function applyGraphicsOverrides( settings.mapOverlay.coordinateGridOpacity = overrides.mapOverlay.coordinateGridOpacity; } + if (overrides.mapOverlay?.staleNukeColor !== undefined) { + // hexToRgb yields 0-255 channels; the stale-nuke uniforms are 0-1 floats. + const rgb = hexToRgb(overrides.mapOverlay.staleNukeColor); + if (rgb !== null) { + settings.mapOverlay.staleNukeR = rgb[0] / 255; + settings.mapOverlay.staleNukeG = rgb[1] / 255; + settings.mapOverlay.staleNukeB = rgb[2] / 255; + } + } if (overrides.railroad?.railMinZoom !== undefined) { settings.railroad.railMinZoom = overrides.railroad.railMinZoom; }