diff --git a/public/data/web_atlas.json b/public/data/web_atlas.json index e5206d2..a0a3150 100644 --- a/public/data/web_atlas.json +++ b/public/data/web_atlas.json @@ -3871,10 +3871,93 @@ ] ] }, - "generator4": { + "cooler7": { "frame": { "x": 1226, "y": 920, + "w": 180, + "h": 156 + }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 180, + "h": 156 + }, + "sourceSize": { + "w": 180, + "h": 156 + }, + "anchor": { + "x": 0.5, + "y": 0.49029721881422206 + }, + "pixelsToUnits": 100.0, + "hitAreas": [ + [ + 79.0, + 10.5, + 79.0, + -16.5, + 65.0, + -29.5, + 55.0, + -32.5, + 42.0, + -28.5, + 41.0, + -57.5, + 38.0, + -63.5, + 19.0, + -76.5, + 7.0, + -76.5, + 1.0, + -75.5, + -37.0, + -51.5, + -45.0, + -41.5, + -44.0, + -12.5, + -63.0, + -8.5, + -73.0, + -2.5, + -77.0, + 0.5, + -83.0, + 15.5, + -83.0, + 41.5, + -80.0, + 44.5, + -72.0, + 51.5, + -52.0, + 49.5, + -48.0, + 63.5, + -37.0, + 71.5, + -16.0, + 71.5, + 4.0, + 68.5, + 65.0, + 32.5, + 70.0, + 27.5 + ] + ] + }, + "generator4": { + "frame": { + "x": 1408, + "y": 920, "w": 172, "h": 154 }, @@ -3956,7 +4039,7 @@ }, "generator3": { "frame": { - "x": 1400, + "x": 1582, "y": 920, "w": 158, "h": 150 @@ -4035,7 +4118,7 @@ }, "black_hole_reactor": { "frame": { - "x": 1560, + "x": 1742, "y": 920, "w": 192, "h": 147 @@ -4356,81 +4439,6 @@ ] ] }, - "cooler7": { - "frame": { - "x": 1754, - "y": 920, - "w": 181, - "h": 143 - }, - "rotated": false, - "trimmed": false, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 181, - "h": 143 - }, - "sourceSize": { - "w": 181, - "h": 143 - }, - "anchor": { - "x": 0.5, - "y": 0.5 - }, - "pixelsToUnits": 100.0, - "hitAreas": [ - [ - 76.5, - -9.5, - 71.5, - -14.5, - 64.5, - -19.5, - 55.5, - -18.5, - 51.5, - -39.5, - 29.5, - -55.5, - -1.5, - -71.5, - -10.5, - -71.5, - -47.5, - -50.5, - -55.5, - -40.5, - -60.5, - -6.5, - -70.5, - -0.5, - -79.5, - 9.5, - -79.5, - 32.5, - -67.5, - 42.5, - -43.5, - 44.5, - -37.5, - 57.5, - -25.5, - 65.5, - -5.5, - 65.5, - -0.5, - 64.5, - 9.5, - 60.5, - 65.5, - 30.5, - 76.5, - 17.5 - ] - ] - }, "cooler8": { "frame": { "x": 2, @@ -4451,58 +4459,58 @@ "h": 143 }, "anchor": { - "x": 0.5, + "x": 0.5000739022397732, "y": 0.5 }, "pixelsToUnits": 100.0, "hitAreas": [ [ - 76.5, - -9.5, - 71.5, - -14.5, - 64.5, - -19.5, - 55.5, - -18.5, - 51.5, - -39.5, - 29.5, + 73.5, + 15.5, + 73.5, + -21.5, + 68.5, + -29.5, + 65.5, + -31.5, + 25.5, -55.5, - -1.5, + -3.5, -71.5, - -10.5, + -11.5, -71.5, - -47.5, - -50.5, - -55.5, - -40.5, - -60.5, - -6.5, - -70.5, - -0.5, + -23.5, + -65.5, + -53.5, + -46.5, + -65.5, + -9.5, + -76.5, + -3.5, -79.5, - 9.5, + 1.5, + -81.5, + 16.5, + -81.5, + 41.5, -79.5, - 32.5, - -67.5, - 42.5, - -43.5, - 44.5, - -37.5, - 57.5, - -25.5, - 65.5, - -5.5, - 65.5, - -0.5, - 64.5, - 9.5, - 60.5, - 65.5, - 30.5, - 76.5, - 17.5 + 45.5, + -72.5, + 47.5, + -44.5, + 40.5, + -44.5, + 62.5, + -40.5, + 67.5, + -33.5, + 67.5, + -24.5, + 62.5, + 0.5, + 61.5, + 62.5, + 27.5 ] ] }, diff --git a/public/data/web_atlas.webp b/public/data/web_atlas.webp index 945c741..4f521df 100644 Binary files a/public/data/web_atlas.webp and b/public/data/web_atlas.webp differ diff --git a/public/icons/anomaly_buff_cooling_pool.webp b/public/icons/anomaly_buff_cooling_pool.webp new file mode 100644 index 0000000..f7ad70c Binary files /dev/null and b/public/icons/anomaly_buff_cooling_pool.webp differ diff --git a/public/icons/anomaly_buff_crowded.webp b/public/icons/anomaly_buff_crowded.webp new file mode 100644 index 0000000..4838522 Binary files /dev/null and b/public/icons/anomaly_buff_crowded.webp differ diff --git a/public/icons/anomaly_buff_isolated.webp b/public/icons/anomaly_buff_isolated.webp new file mode 100644 index 0000000..ff16c93 Binary files /dev/null and b/public/icons/anomaly_buff_isolated.webp differ diff --git a/public/icons/anomaly_buff_waterside.webp b/public/icons/anomaly_buff_waterside.webp new file mode 100644 index 0000000..f96e8be Binary files /dev/null and b/public/icons/anomaly_buff_waterside.webp differ diff --git a/public/icons/cooler7.webp b/public/icons/cooler7.webp index 2f5dfc8..02a55eb 100644 Binary files a/public/icons/cooler7.webp and b/public/icons/cooler7.webp differ diff --git a/public/icons/cooler8.webp b/public/icons/cooler8.webp index 808e7b9..45d6ea2 100644 Binary files a/public/icons/cooler8.webp and b/public/icons/cooler8.webp differ diff --git a/public/icons/status_gauge.webp b/public/icons/status_gauge.webp new file mode 100644 index 0000000..11db4a1 Binary files /dev/null and b/public/icons/status_gauge.webp differ diff --git a/public/icons/status_idle.webp b/public/icons/status_idle.webp new file mode 100644 index 0000000..08b4a3a Binary files /dev/null and b/public/icons/status_idle.webp differ diff --git a/public/icons/status_offline.webp b/public/icons/status_offline.webp new file mode 100644 index 0000000..1ba550d Binary files /dev/null and b/public/icons/status_offline.webp differ diff --git a/public/icons/status_overheated.webp b/public/icons/status_overheated.webp new file mode 100644 index 0000000..ce48c8e Binary files /dev/null and b/public/icons/status_overheated.webp differ diff --git a/src/lib/components/canvas/PixiCanvas.svelte b/src/lib/components/canvas/PixiCanvas.svelte index 2953613..ac9f5f7 100755 --- a/src/lib/components/canvas/PixiCanvas.svelte +++ b/src/lib/components/canvas/PixiCanvas.svelte @@ -7,7 +7,15 @@ uiState, viewportState, } from "../../state"; - import { createPlacement } from "../../data/placements"; + import { + createPlacement, + gameStatuses, + placementFillPercent, + } from "../../data/placements"; + import { BUILDINGS, findBuilding } from "@reactor2/solver"; + import { ratedPlacements, ratingShifts } from "../../simulation/simulator"; + import { anomalyIconFor, STATE_ICON } from "../../data/boardIcons"; + import type { BuildingOverlay } from "../../pixi/gridPainter"; import { onMount, onDestroy, untrack } from "svelte"; import { Application, Container, Rectangle } from "pixi.js"; import { loadAtlas } from "../../pixi/atlas"; @@ -839,6 +847,55 @@ recenterGrid(); }); + /* + * What each visible building wears beyond its sprite and pad, aligned with + * `visiblePlacements`. + * + * The badge figure is a fraction of what the scorer rated the building for on + * this board — the readout's ceiling, so a badge reading 70% and the card's + * `600 / 852` are one measurement — and only computed while the setting is + * on. The anomaly icon shows where the scorer rated the building off its + * plain tier, so it marks exactly the buildings an anomaly moved. Both rate + * the whole board in one pass, since a rule can rate a tile by what its + * neighbours are, and both take the rules from `layoutState` exactly as the + * readout does. + */ + let buildingOverlays = $derived.by((): BuildingOverlay[] => { + const placements = uiState.visiblePlacements; + const grid = layoutState.grid; + const prestige = layoutState.placementPrestige; + const anomaly = layoutState.placementAnomaly; + // Rated unconditionally: the state icons need the ceilings as much as the + // gauges do — a generator is only "wasting heat" at full capacity. + const rated = ratedPlacements( + grid, + BUILDINGS, + placements, + prestige, + anomaly, + ); + const states = gameStatuses( + placements, + rated, + anomaly.rule === "shared_cooling", + ); + const showFill = uiState.fillBadges; + const shifts = + anomaly.rule === "baseline" + ? null + : ratingShifts(grid, BUILDINGS, placements, prestige, anomaly); + return placements.map((p, i) => { + const r = rated[i]; + const role = findBuilding(p.buildingId)?.type; + return { + fill: showFill && r ? placementFillPercent(p, r) : null, + stateIcon: STATE_ICON[states[i]], + anomalyIcon: + shifts && role ? anomalyIconFor(anomaly, shifts[i], role) : null, + }; + }); + }); + $effect(() => { const curW = layoutState.width; const curH = layoutState.height; @@ -848,6 +905,7 @@ // inspector reads the same getter — so the card can never describe a // building that is not the one being drawn. const activePlacements = uiState.visiblePlacements; + const overlays = buildingOverlays; // Ghosts only while restore mode is on — see `editorState.restoreMode`. const ghosts = editorState.restoreMode @@ -875,7 +933,13 @@ * correctness depend on an accidental re-run. Both edges are plain * variables and the paint is spelled out. */ - gridRenderer.updateState(currentGrid, curW, curH, activePlacements); + gridRenderer.updateState( + currentGrid, + curW, + curH, + activePlacements, + overlays, + ); gridRenderer.setGhosts(ghosts); } }); diff --git a/src/lib/components/modals/SettingsModal.svelte b/src/lib/components/modals/SettingsModal.svelte index 0a22825..eb80bcd 100755 --- a/src/lib/components/modals/SettingsModal.svelte +++ b/src/lib/components/modals/SettingsModal.svelte @@ -1,6 +1,12 @@