mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 06:20:44 +00:00
Add nuke fallout color graphics option (#4355)
## What Adds a **Nuke fallout color** option to the in-game graphics settings modal (Effects section), letting players recolor the fallout tint left on territory after a nuke.  ## How Mirrors the existing **Ocean color** override pattern: - `GraphicsOverrides.ts` — adds `staleNukeColor` (hex string) to the `mapOverlay` override schema. - `RenderOverrides.ts` — `applyGraphicsOverrides` parses the hex and writes the renderer's `staleNukeR/G/B` 0–1 float channels (`hexToRgb` yields 0–255, so it divides by 255). - `GraphicsSettingsModal.ts` — new hex-text + native color-picker row, default computed from `render-settings.json`. - `en.json` — `nuke_color_label` / `nuke_color_desc`. The value persists via `UserSettings.graphicsOverrides()` and is cleared by the modal's existing "Reset to defaults". The render debug GUI already exposes the same setting as **Stale Nuke Color** (Map Overlay), so no change was needed there. ## Testing - `tsc --noEmit` clean. - Verified in a headless solo game: the row renders with the green default (`#0d8c12`), changing it persists `mapOverlay.staleNukeColor`, and `applyGraphicsOverrides("#ff0000")` produces `staleNukeR=1, G=0, B=0`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -553,6 +553,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",
|
||||
|
||||
@@ -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 {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex gap-3 items-center w-full text-left p-3 hover:bg-slate-700 rounded-sm text-white transition-colors"
|
||||
>
|
||||
<div class="flex-1">
|
||||
<div class="font-medium">
|
||||
${translateText("graphics_setting.nuke_color_label")}
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${translateText("graphics_setting.nuke_color_desc")}
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
.value=${nukeColor}
|
||||
placeholder=${NUKE_COLOR_DEFAULT}
|
||||
spellcheck="false"
|
||||
@change=${this.onNukeColorChange}
|
||||
class="w-24 px-2 py-1 bg-slate-900 border border-slate-500 rounded-sm text-sm text-white font-mono"
|
||||
/>
|
||||
<input
|
||||
type="color"
|
||||
.value=${nukeColor}
|
||||
@input=${this.onNukeColorChange}
|
||||
class="w-10 h-8 bg-transparent border border-slate-500 rounded-sm cursor-pointer"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="px-3 py-1 text-xs font-semibold text-slate-400 uppercase tracking-wider mt-2"
|
||||
>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user