Icons update (#1562)

## Description:

Add option toggle for structure sprites
Add new icons
Add new shapes
Add scaling for text and bigger text

<img width="853" height="548" alt="image"
src="https://github.com/user-attachments/assets/2f3e0b3d-af34-485b-a897-11fd74f6c51a"
/>
<img width="690" height="375" alt="image"
src="https://github.com/user-attachments/assets/9dea3fc2-6054-473d-9530-0222e49948ac"
/>


## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I have read and accepted the CLA aggreement (only required once).

## Please put your Discord username so you can be contacted if a bug or
regression is found:

Mr. Box

---------

Co-authored-by: evanpelle <evanpelle@gmail.com>
This commit is contained in:
Vivacious Box
2025-08-04 19:06:53 +02:00
committed by GitHub
parent fcd6f5d404
commit b479d04c6c
11 changed files with 280 additions and 98 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 B

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 310 B

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 B

After

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 B

After

Width:  |  Height:  |  Size: 235 B

+4
View File
@@ -276,6 +276,10 @@
"special_effects_desc": "Toggle special effects. Deactivate to improve performances",
"special_effects_enabled": "Special effects enabled",
"special_effects_disabled": "Special effects disabled",
"structure_sprites_label": "Structure Sprites",
"structure_sprites_desc": "Toggle structure sprites",
"structure_sprites_enabled": "Structure Sprites enabled",
"structure_sprites_disabled": "Structure Sprites disabled",
"anonymous_names_label": "Hidden Names",
"anonymous_names_desc": "Hide real player names with random ones on your screen.",
"anonymous_names_enabled": "Anonymous names enabled",
+18
View File
@@ -125,6 +125,15 @@ export class UserSettingModal extends LitElement {
console.log("💥 Special effects:", enabled ? "ON" : "OFF");
}
private toggleStructureSprites(e: CustomEvent<{ checked: boolean }>) {
const enabled = e.detail?.checked;
if (typeof enabled !== "boolean") return;
this.userSettings.set("settings.structureSprites", enabled);
console.log("🏠 Structure sprites:", enabled ? "ON" : "OFF");
}
private toggleAnonymousNames(e: CustomEvent<{ checked: boolean }>) {
const enabled = e.detail?.checked;
if (typeof enabled !== "boolean") return;
@@ -291,6 +300,15 @@ export class UserSettingModal extends LitElement {
@change=${this.toggleFxLayer}
></setting-toggle>
<!-- 🏠 Structure Sprites -->
<setting-toggle
label="${translateText("user_setting.structure_sprites_label")}"
description="${translateText("user_setting.structure_sprites_desc")}"
id="structure_sprites-toggle"
.checked=${this.userSettings.structureSprites()}
@change=${this.toggleStructureSprites}
></setting-toggle>
<!-- 🖱️ Left Click Menu -->
<setting-toggle
label="${translateText("user_setting.left_click_label")}"
@@ -1,5 +1,6 @@
import { html, LitElement } from "lit";
import { customElement, query, state } from "lit/decorators.js";
import structureIcon from "../../../../resources/images/CityIconWhite.svg";
import darkModeIcon from "../../../../resources/images/DarkModeIconWhite.svg";
import emojiIcon from "../../../../resources/images/EmojiIconWhite.svg";
import exitIcon from "../../../../resources/images/ExitIconWhite.svg";
@@ -93,6 +94,11 @@ export class SettingsModal extends LitElement implements Layer {
this.requestUpdate();
}
private onToggleStructureSpritesButtonClick() {
this.userSettings.toggleStructureSprites();
this.requestUpdate();
}
private onToggleSpecialEffectsButtonClick() {
this.userSettings.toggleFxLayer();
this.requestUpdate();
@@ -259,6 +265,33 @@ export class SettingsModal extends LitElement implements Layer {
</div>
</button>
<button
class="flex gap-3 items-center w-full text-left p-3 hover:bg-slate-700 rounded text-white transition-colors"
@click="${this.onToggleStructureSpritesButtonClick}"
>
<img
src=${structureIcon}
alt="structureSprites"
width="20"
height="20"
/>
<div class="flex-1">
<div class="font-medium">
${translateText("user_setting.structure_sprites_label")}
</div>
<div class="text-sm text-slate-400">
${this.userSettings.structureSprites()
? translateText("user_setting.structure_sprites_enabled")
: translateText("user_setting.structure_sprites_disabled")}
</div>
</div>
<div class="text-sm text-slate-400">
${this.userSettings.structureSprites()
? translateText("user_setting.on")
: translateText("user_setting.off")}
</div>
</button>
<button
class="flex gap-3 items-center w-full text-left p-3 hover:bg-slate-700 rounded text-white transition-colors"
@click="${this.onToggleRandomNameModeButtonClick}"
+210 -94
View File
@@ -16,7 +16,7 @@ import { ToggleStructureEvent } from "../../InputHandler";
import { TransformHandler } from "../TransformHandler";
import { Layer } from "./Layer";
type ShapeType = "triangle" | "square" | "octagon" | "circle";
type ShapeType = "triangle" | "square" | "pentagon" | "octagon" | "circle";
class StructureRenderInfo {
public isOnScreen: boolean = false;
@@ -25,6 +25,7 @@ class StructureRenderInfo {
public owner: PlayerID,
public iconContainer: PIXI.Container,
public levelContainer: PIXI.Container,
public dotContainer: PIXI.Container,
public level: number = 0,
public underConstruction: boolean = true,
) {}
@@ -32,20 +33,31 @@ class StructureRenderInfo {
const STRUCTURE_SHAPES: Partial<Record<UnitType, ShapeType>> = {
[UnitType.City]: "circle",
[UnitType.Port]: "circle",
[UnitType.Port]: "pentagon",
[UnitType.Factory]: "circle",
[UnitType.DefensePost]: "octagon",
[UnitType.SAMLauncher]: "square",
[UnitType.MissileSilo]: "triangle",
};
const ZOOM_THRESHOLD = 3.5;
const ICON_SIZE = 24;
const OFFSET_ZOOM_Y = 5; // offset for the y position of the icon to avoid hiding the structure beneath
const LEVEL_SCALE_FACTOR = 3;
const ICON_SCALE_FACTOR_ZOOMED_IN = 3.5;
const ICON_SCALE_FACTOR_ZOOMED_OUT = 1.4;
const DOTS_ZOOM_THRESHOLD = 0.5;
const ZOOM_THRESHOLD = 4.3;
const ICON_SIZE = {
circle: 28,
octagon: 28,
pentagon: 30,
square: 28,
triangle: 28,
};
const OFFSET_ZOOM_Y = 4; // offset for the y position of the level over the sprite
export class StructureIconsLayer implements Layer {
private pixicanvas: HTMLCanvasElement;
private iconsStage: PIXI.Container;
private levelsStage: PIXI.Container;
private dotsStage: PIXI.Container;
private shouldRedraw: boolean = true;
private textureCache: Map<string, PIXI.Texture> = new Map();
private theme: Theme;
@@ -72,6 +84,7 @@ export class StructureIconsLayer implements Layer {
{ visible: true, iconPath: SAMMissileIcon, image: null },
],
]);
private renderSprites = true;
constructor(
private game: GameView,
@@ -95,19 +108,22 @@ export class StructureIconsLayer implements Layer {
this.iconsStage = new PIXI.Container();
this.iconsStage.position.set(0, 0);
this.iconsStage.width = this.pixicanvas.width;
this.iconsStage.height = this.pixicanvas.height;
this.iconsStage.setSize(this.pixicanvas.width, this.pixicanvas.height);
this.levelsStage = new PIXI.Container();
this.levelsStage.position.set(0, 0);
this.levelsStage.width = this.pixicanvas.width;
this.levelsStage.height = this.pixicanvas.height;
this.levelsStage.setSize(this.pixicanvas.width, this.pixicanvas.height);
this.dotsStage = new PIXI.Container();
this.dotsStage.position.set(0, 0);
this.dotsStage.setSize(this.pixicanvas.width, this.pixicanvas.height);
await this.renderer.init({
canvas: this.pixicanvas,
resolution: 1,
width: this.pixicanvas.width,
height: this.pixicanvas.height,
antialias: false,
clearBeforeRender: true,
backgroundAlpha: 0,
backgroundColor: 0x00000000,
@@ -168,6 +184,8 @@ export class StructureIconsLayer implements Layer {
this.handleInactiveUnit(unitView);
}
});
this.renderSprites =
this.game.config().userSettings()?.structureSprites() ?? true;
}
private toggleStructure(toggleStructureType: UnitType | null): void {
@@ -227,12 +245,17 @@ export class StructureIconsLayer implements Layer {
}
if (structureInfos) {
render.iconContainer.alpha = structureInfos.visible ? 1 : 0.3;
render.dotContainer.alpha = structureInfos.visible ? 1 : 0.3;
if (structureInfos.visible && focusStructure) {
render.iconContainer.filters = [
new OutlineFilter({ thickness: 2, color: "rgb(255, 255, 255)" }),
];
render.dotContainer.filters = [
new OutlineFilter({ thickness: 2, color: "rgb(255, 255, 255)" }),
];
} else {
render.iconContainer.filters = [];
render.dotContainer.filters = [];
}
}
}
@@ -247,7 +270,9 @@ export class StructureIconsLayer implements Layer {
) {
render.underConstruction = false;
render.iconContainer?.destroy();
render.dotContainer?.destroy();
render.iconContainer = this.createIconSprite(unit);
render.dotContainer = this.createDotSprite(unit);
this.modifyVisibility(render);
this.shouldRedraw = true;
}
@@ -257,7 +282,9 @@ export class StructureIconsLayer implements Layer {
if (render.owner !== unit.owner().id()) {
render.owner = unit.owner().id();
render.iconContainer?.destroy();
render.dotContainer?.destroy();
render.iconContainer = this.createIconSprite(unit);
render.dotContainer = this.createDotSprite(unit);
this.modifyVisibility(render);
this.shouldRedraw = true;
}
@@ -268,8 +295,10 @@ export class StructureIconsLayer implements Layer {
render.level = unit.level();
render.iconContainer?.destroy();
render.levelContainer?.destroy();
render.dotContainer?.destroy();
render.iconContainer = this.createIconSprite(unit);
render.levelContainer = this.createLevelSprite(unit);
render.dotContainer = this.createDotSprite(unit);
this.modifyVisibility(render);
this.shouldRedraw = true;
}
@@ -291,17 +320,19 @@ export class StructureIconsLayer implements Layer {
}
if (this.transformHandler.hasChanged() || this.shouldRedraw) {
if (this.transformHandler.scale > ZOOM_THRESHOLD) {
if (this.transformHandler.scale > ZOOM_THRESHOLD && this.renderSprites) {
this.renderer.render(this.levelsStage);
} else {
} else if (this.transformHandler.scale > DOTS_ZOOM_THRESHOLD) {
this.renderer.render(this.iconsStage);
} else {
this.renderer.render(this.dotsStage);
}
this.shouldRedraw = false;
}
mainContext.drawImage(this.renderer.canvas, 0, 0);
}
private createTexture(unit: UnitView): PIXI.Texture {
private createTexture(unit: UnitView, renderIcon: boolean): PIXI.Texture {
const isConstruction = unit.type() === UnitType.Construction;
const constructionType = unit.constructionType();
if (isConstruction && constructionType === undefined) {
@@ -312,15 +343,22 @@ export class StructureIconsLayer implements Layer {
}
const structureType = isConstruction ? constructionType! : unit.type();
const cacheKey = isConstruction
? `construction-${structureType}`
: `${unit.owner().id()}-${structureType}`;
? `construction-${structureType}` + (renderIcon ? "-icon" : "")
: `${this.theme.territoryColor(unit.owner()).toRgbString()}-${structureType}` +
(renderIcon ? "-icon" : "");
if (this.textureCache.has(cacheKey)) {
return this.textureCache.get(cacheKey)!;
}
const shape = STRUCTURE_SHAPES[structureType];
const texture = shape
? this.createIcon(unit.owner(), structureType, isConstruction, shape)
? this.createIcon(
unit.owner(),
structureType,
isConstruction,
shape,
renderIcon,
)
: PIXI.Texture.EMPTY;
this.textureCache.set(cacheKey, texture);
@@ -331,11 +369,16 @@ export class StructureIconsLayer implements Layer {
owner: PlayerView,
structureType: UnitType,
isConstruction: boolean,
shape: "triangle" | "square" | "octagon" | "circle",
) {
shape: ShapeType,
renderIcon: boolean,
): PIXI.Texture {
const structureCanvas = document.createElement("canvas");
structureCanvas.width = ICON_SIZE;
structureCanvas.height = ICON_SIZE;
let iconSize = ICON_SIZE[shape];
if (!renderIcon) {
iconSize /= 2.5;
}
structureCanvas.width = Math.ceil(iconSize);
structureCanvas.height = Math.ceil(iconSize);
const context = structureCanvas.getContext("2d")!;
let borderColor: string;
@@ -345,35 +388,37 @@ export class StructureIconsLayer implements Layer {
} else {
context.fillStyle = this.theme
.territoryColor(owner)
.lighten(0.06)
.lighten(0.13)
.alpha(renderIcon ? 0.65 : 1)
.toRgbString();
borderColor = this.theme.borderColor(owner).darken(0.08).toRgbString();
const darken = this.theme.borderColor(owner).isLight() ? 0.17 : 0.15;
borderColor = this.theme.borderColor(owner).darken(darken).toRgbString();
}
context.strokeStyle = borderColor;
context.lineWidth = 1;
const halfIconSize = iconSize / 2;
switch (shape) {
case "triangle":
context.beginPath();
context.moveTo(ICON_SIZE / 2, 0); // Top
context.lineTo(ICON_SIZE, ICON_SIZE); // Bottom right
context.lineTo(0, ICON_SIZE); // Bottom left
context.moveTo(halfIconSize, 1); // Top
context.lineTo(iconSize - 1, iconSize - 1); // Bottom right
context.lineTo(0, iconSize - 1); // Bottom left
context.closePath();
context.fill();
context.stroke();
break;
case "square":
context.fillRect(0, 0, ICON_SIZE - 2, ICON_SIZE - 2);
context.strokeRect(0.5, 0.5, ICON_SIZE - 3, ICON_SIZE - 3);
context.fillRect(1, 1, iconSize - 2, iconSize - 2);
context.strokeRect(1, 1, iconSize - 3, iconSize - 3);
break;
case "octagon":
{
const cx = ICON_SIZE / 2;
const cy = ICON_SIZE / 2;
const r = ICON_SIZE / 2 - 1;
const cx = halfIconSize;
const cy = halfIconSize;
const r = halfIconSize - 1;
const step = (Math.PI * 2) / 8;
context.beginPath();
@@ -392,13 +437,35 @@ export class StructureIconsLayer implements Layer {
context.stroke();
}
break;
case "pentagon":
{
const cx = halfIconSize;
const cy = halfIconSize;
const r = halfIconSize - 1;
const step = (Math.PI * 2) / 5;
context.beginPath();
for (let i = 0; i < 5; i++) {
const angle = step * i - Math.PI / 2; // rotate to have flat base or point up
const x = cx + r * Math.cos(angle);
const y = cy + r * Math.sin(angle);
if (i === 0) {
context.moveTo(x, y);
} else {
context.lineTo(x, y);
}
}
context.closePath();
context.fill();
context.stroke();
}
break;
case "circle":
context.beginPath();
context.arc(
ICON_SIZE / 2,
ICON_SIZE / 2,
ICON_SIZE / 2 - 1,
halfIconSize,
halfIconSize,
halfIconSize - 1,
0,
Math.PI * 2,
);
@@ -416,81 +483,111 @@ export class StructureIconsLayer implements Layer {
return PIXI.Texture.from(structureCanvas);
}
const SHAPE_OFFSETS = {
triangle: [4, 8],
square: [3, 3],
octagon: [4, 4],
circle: [4, 4],
};
const [offsetX, offsetY] = SHAPE_OFFSETS[shape] || [0, 0];
context.drawImage(
this.getImageColored(structureInfo.image, borderColor),
offsetX,
offsetY,
);
if (renderIcon) {
const SHAPE_OFFSETS = {
triangle: [6, 11],
square: [5, 5],
octagon: [6, 6],
pentagon: [7, 7],
circle: [6, 6],
};
const [offsetX, offsetY] = SHAPE_OFFSETS[shape] || [0, 0];
context.drawImage(
this.getImageColored(structureInfo.image, borderColor),
offsetX,
offsetY,
);
}
return PIXI.Texture.from(structureCanvas);
}
private createLevelSprite(unit: UnitView): PIXI.Container {
return this.createUnitContainer(unit, {
addIcon: false,
type: "level",
stage: this.levelsStage,
});
}
private createDotSprite(unit: UnitView): PIXI.Container {
return this.createUnitContainer(unit, {
type: "dot",
stage: this.dotsStage,
});
}
private createIconSprite(unit: UnitView): PIXI.Container {
return this.createUnitContainer(unit, {
addIcon: true,
type: "icon",
stage: this.iconsStage,
});
}
private createUnitContainer(
unit: UnitView,
options: { addIcon?: boolean; stage: PIXI.Container },
options: { type?: "icon" | "dot" | "level"; stage: PIXI.Container },
): PIXI.Container {
const parentContainer = new PIXI.Container();
const tile = unit.tile();
const worldX = this.game.x(tile);
const worldY = this.game.y(tile);
const screenPos = this.transformHandler.worldToScreenCoordinates(
new Cell(worldX, worldY),
);
const worldPos = new Cell(this.game.x(tile), this.game.y(tile));
const screenPos = this.transformHandler.worldToScreenCoordinates(worldPos);
if (options.addIcon) {
const sprite = new PIXI.Sprite(this.createTexture(unit));
sprite.anchor.set(0.5, 0.5);
const { type, stage } = options;
const scale = this.transformHandler.scale;
const spritesEnabled = this.game
.config()
.userSettings()
?.structureSprites?.();
// Add sprite if needed
if (type === "icon" || type === "dot") {
const texture = this.createTexture(unit, type === "icon");
const sprite = new PIXI.Sprite(texture);
sprite.anchor.set(0.5);
parentContainer.addChild(sprite);
}
if (unit.level() > 1) {
// Add level text if needed
if ((type === "icon" || type === "level") && unit.level() > 1) {
const text = new PIXI.BitmapText({
text: unit.level().toString(),
style: {
fontFamily: "round_6x6_modified",
fontSize: 12,
fontSize: 14,
},
});
text.anchor.set(0.5, 0.5);
text.position.y = -ICON_SIZE / 2 - 2;
text.anchor.set(0.5);
const unitType =
unit.type() === UnitType.Construction
? unit.constructionType()
: unit.type();
const shape = STRUCTURE_SHAPES[unitType!];
if (shape !== undefined) {
text.position.y = Math.round(-ICON_SIZE[shape] / 2 - 2);
}
parentContainer.addChild(text);
}
// Positioning
const posX = Math.round(screenPos.x);
let posY = Math.round(screenPos.y);
if (type === "level" && scale >= ZOOM_THRESHOLD && spritesEnabled) {
posY = Math.round(screenPos.y - scale * OFFSET_ZOOM_Y);
}
parentContainer.position.set(posX, posY);
if (this.transformHandler.scale >= ZOOM_THRESHOLD) {
posY = Math.round(
screenPos.y - this.transformHandler.scale * OFFSET_ZOOM_Y,
);
// Scaling
if (type === "icon") {
const s =
scale >= ZOOM_THRESHOLD && !spritesEnabled
? Math.max(1, scale / ICON_SCALE_FACTOR_ZOOMED_IN)
: Math.min(1, scale / ICON_SCALE_FACTOR_ZOOMED_OUT);
parentContainer.scale.set(s);
} else if (type === "level") {
parentContainer.scale.set(Math.max(1, scale / LEVEL_SCALE_FACTOR));
}
parentContainer.position.set(posX, posY);
parentContainer.scale.set(Math.min(1, this.transformHandler.scale));
options.stage.addChild(parentContainer);
stage.addChild(parentContainer);
return parentContainer;
}
@@ -511,23 +608,27 @@ export class StructureIconsLayer implements Layer {
private computeNewLocation(render: StructureRenderInfo) {
const tile = render.unit.tile();
const worldX = this.game.x(tile);
const worldY = this.game.y(tile);
const screenPos = this.transformHandler.worldToScreenCoordinates(
new Cell(worldX, worldY),
);
const worldPos = new Cell(this.game.x(tile), this.game.y(tile));
const screenPos = this.transformHandler.worldToScreenCoordinates(worldPos);
screenPos.x = Math.round(screenPos.x);
if (this.transformHandler.scale >= ZOOM_THRESHOLD) {
// Adjust the y position based on zoom level to avoid hiding the structure beneath
screenPos.y = Math.round(
screenPos.y - this.transformHandler.scale * OFFSET_ZOOM_Y,
);
} else {
screenPos.y = Math.round(screenPos.y);
}
// Check if the sprite is on screen (with margin for partial visibility)
const margin = ICON_SIZE;
const scale = this.transformHandler.scale;
screenPos.y = Math.round(
scale >= ZOOM_THRESHOLD &&
this.game.config().userSettings()?.structureSprites()
? screenPos.y - scale * OFFSET_ZOOM_Y
: screenPos.y,
);
const type =
render.unit.type() === UnitType.Construction
? render.unit.constructionType()
: render.unit.type();
const margin =
type !== undefined && STRUCTURE_SHAPES[type] !== undefined
? ICON_SIZE[STRUCTURE_SHAPES[type]]
: 28;
const onScreen =
screenPos.x + margin > 0 &&
screenPos.x - margin < this.pixicanvas.width &&
@@ -535,21 +636,34 @@ export class StructureIconsLayer implements Layer {
screenPos.y - margin < this.pixicanvas.height;
if (onScreen) {
if (this.transformHandler.scale > ZOOM_THRESHOLD) {
render.levelContainer.x = screenPos.x;
render.levelContainer.y = screenPos.y;
} else {
render.iconContainer.x = screenPos.x;
render.iconContainer.y = screenPos.y;
render.iconContainer.scale.set(
Math.min(1, this.transformHandler.scale),
if (scale > ZOOM_THRESHOLD) {
const target = this.game.config().userSettings()?.structureSprites()
? render.levelContainer
: render.iconContainer;
target.position.set(screenPos.x, screenPos.y);
target.scale.set(
Math.max(
1,
scale /
(target === render.levelContainer
? LEVEL_SCALE_FACTOR
: ICON_SCALE_FACTOR_ZOOMED_IN),
),
);
} else if (scale > DOTS_ZOOM_THRESHOLD) {
render.iconContainer.position.set(screenPos.x, screenPos.y);
render.iconContainer.scale.set(
Math.min(1, scale / ICON_SCALE_FACTOR_ZOOMED_OUT),
);
} else {
render.dotContainer.position.set(screenPos.x, screenPos.y);
}
}
if (render.isOnScreen !== onScreen) {
// prevent unnecessary updates
render.isOnScreen = onScreen;
render.iconContainer.visible = onScreen;
render.dotContainer.visible = onScreen;
render.levelContainer.visible = onScreen;
}
}
@@ -561,6 +675,7 @@ export class StructureIconsLayer implements Layer {
unitView.owner().id(),
this.createIconSprite(unitView),
this.createLevelSprite(unitView),
this.createDotSprite(unitView),
unitView.level(),
unitView.type() === UnitType.Construction,
);
@@ -573,6 +688,7 @@ export class StructureIconsLayer implements Layer {
private deleteStructure(render: StructureRenderInfo) {
render.iconContainer?.destroy();
render.levelContainer?.destroy();
render.dotContainer?.destroy();
this.renders = this.renders.filter((r) => r.unit !== render.unit);
this.seenUnits.delete(render.unit);
}
+5 -2
View File
@@ -21,7 +21,7 @@ const underConstructionColor = colord({ r: 150, g: 150, b: 150 });
const BASE_BORDER_RADIUS = 16.5;
const BASE_TERRITORY_RADIUS = 13.5;
const RADIUS_SCALE_FACTOR = 0.5;
const ZOOM_THRESHOLD = 3.5; // below this zoom level, structures are not rendered
const ZOOM_THRESHOLD = 4.3; // below this zoom level, structures are not rendered
interface UnitRenderConfig {
icon: string;
@@ -146,7 +146,10 @@ export class StructureLayer implements Layer {
}
renderLayer(context: CanvasRenderingContext2D) {
if (this.transformHandler.scale <= ZOOM_THRESHOLD) {
if (
this.transformHandler.scale <= ZOOM_THRESHOLD ||
!this.game.config().userSettings()?.structureSprites()
) {
return;
}
context.drawImage(
+2 -2
View File
@@ -1,11 +1,11 @@
import { html, LitElement } from "lit";
import { customElement } from "lit/decorators.js";
import portIcon from "../../../../resources/images/AnchorIcon.png";
import cityIcon from "../../../../resources/images/CityIconWhite.svg";
import factoryIcon from "../../../../resources/images/FactoryIconWhite.svg";
import missileSiloIcon from "../../../../resources/images/MissileSiloUnit.png";
import portIcon from "../../../../resources/images/PortIcon.svg";
import samLauncherIcon from "../../../../resources/images/SamLauncherUnitWhite.png";
import defensePostIcon from "../../../../resources/images/ShieldIconWhite.svg";
import samLauncherIcon from "../../../../resources/non-commercial/svg/SamLauncherIconWhite.svg";
import { EventBus } from "../../../core/EventBus";
import { UnitType } from "../../../core/game/Game";
import { GameView } from "../../../core/game/GameView";
+8
View File
@@ -40,6 +40,10 @@ export class UserSettings {
return this.get("settings.specialEffects", true);
}
structureSprites() {
return this.get("settings.structureSprites", true);
}
darkMode() {
return this.get("settings.darkMode", false);
}
@@ -90,6 +94,10 @@ export class UserSettings {
this.set("settings.specialEffects", !this.fxLayer());
}
toggleStructureSprites() {
this.set("settings.structureSprites", !this.structureSprites());
}
toggleTerritoryPatterns() {
this.set("settings.territoryPatterns", !this.territoryPatterns());
}