mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-19 11:35:02 +00:00
Merge branch 'v25'
This commit is contained in:
@@ -170,7 +170,7 @@ export class RailroadLayer implements Layer {
|
||||
const owner = this.game.owner(tile);
|
||||
const recipient = owner.isPlayer() ? owner : null;
|
||||
const color = recipient
|
||||
? this.theme.railroadColor(recipient)
|
||||
? recipient.borderColor()
|
||||
: new Colord({ r: 255, g: 255, b: 255, a: 1 });
|
||||
this.context.fillStyle = color.toRgbString();
|
||||
this.paintRailRects(this.context, x, y, railType);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { extend } from "colord";
|
||||
import a11yPlugin from "colord/plugins/a11y";
|
||||
import { OutlineFilter } from "pixi-filters";
|
||||
import * as PIXI from "pixi.js";
|
||||
import bitmapFont from "../../../../resources/fonts/round_6x6_modified.xml";
|
||||
@@ -16,6 +18,8 @@ import { ToggleStructureEvent } from "../../InputHandler";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
extend([a11yPlugin]);
|
||||
|
||||
type ShapeType = "triangle" | "square" | "pentagon" | "octagon" | "circle";
|
||||
|
||||
class StructureRenderInfo {
|
||||
@@ -344,7 +348,7 @@ export class StructureIconsLayer implements Layer {
|
||||
const structureType = isConstruction ? constructionType! : unit.type();
|
||||
const cacheKey = isConstruction
|
||||
? `construction-${structureType}` + (renderIcon ? "-icon" : "")
|
||||
: `${this.theme.territoryColor(unit.owner()).toRgbString()}-${structureType}` +
|
||||
: `${unit.owner().territoryColor().toRgbString()}-${structureType}` +
|
||||
(renderIcon ? "-icon" : "");
|
||||
if (this.textureCache.has(cacheKey)) {
|
||||
return this.textureCache.get(cacheKey)!;
|
||||
@@ -381,18 +385,23 @@ export class StructureIconsLayer implements Layer {
|
||||
structureCanvas.height = Math.ceil(iconSize);
|
||||
const context = structureCanvas.getContext("2d")!;
|
||||
|
||||
const tc = owner.territoryColor();
|
||||
const bc = owner.borderColor();
|
||||
|
||||
const darker = bc.luminance() < tc.luminance() ? bc : tc;
|
||||
const lighter = bc.luminance() < tc.luminance() ? tc : bc;
|
||||
|
||||
let borderColor: string;
|
||||
if (isConstruction) {
|
||||
context.fillStyle = "rgb(198, 198, 198)";
|
||||
borderColor = "rgb(128, 127, 127)";
|
||||
} else {
|
||||
context.fillStyle = this.theme
|
||||
.territoryColor(owner)
|
||||
context.fillStyle = lighter
|
||||
.lighten(0.13)
|
||||
.alpha(renderIcon ? 0.65 : 1)
|
||||
.toRgbString();
|
||||
const darken = this.theme.borderColor(owner).isLight() ? 0.17 : 0.15;
|
||||
borderColor = this.theme.borderColor(owner).darken(darken).toRgbString();
|
||||
const darken = darker.isLight() ? 0.17 : 0.15;
|
||||
borderColor = darker.darken(darken).toRgbString();
|
||||
}
|
||||
|
||||
context.strokeStyle = borderColor;
|
||||
|
||||
@@ -190,7 +190,7 @@ export class StructureLayer implements Layer {
|
||||
new Cell(this.game.x(tile), this.game.y(tile)),
|
||||
unit.type() === UnitType.Construction
|
||||
? underConstructionColor
|
||||
: this.theme.territoryColor(unit.owner()),
|
||||
: unit.owner().territoryColor(),
|
||||
130,
|
||||
);
|
||||
}
|
||||
@@ -203,7 +203,7 @@ export class StructureLayer implements Layer {
|
||||
|
||||
const config = this.unitConfigs[unitType];
|
||||
let icon: HTMLImageElement | undefined;
|
||||
let borderColor = this.theme.borderColor(unit.owner());
|
||||
let borderColor = unit.owner().borderColor();
|
||||
|
||||
// Handle cooldown states and special icons
|
||||
if (unit.type() === UnitType.Construction) {
|
||||
@@ -244,7 +244,7 @@ export class StructureLayer implements Layer {
|
||||
height: number,
|
||||
unit: UnitView,
|
||||
) {
|
||||
let color = this.theme.borderColor(unit.owner());
|
||||
let color = unit.owner().borderColor();
|
||||
if (unit.type() === UnitType.Construction) {
|
||||
color = underConstructionColor;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
AlternateViewEvent,
|
||||
DragEvent,
|
||||
MouseOverEvent,
|
||||
RefreshGraphicsEvent,
|
||||
} from "../../InputHandler";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import { Layer } from "./Layer";
|
||||
@@ -75,11 +74,6 @@ export class TerritoryLayer implements Layer {
|
||||
}
|
||||
|
||||
tick() {
|
||||
const prev = this.cachedTerritoryPatternsEnabled;
|
||||
this.cachedTerritoryPatternsEnabled = this.userSettings.territoryPatterns();
|
||||
if (prev !== undefined && prev !== this.cachedTerritoryPatternsEnabled) {
|
||||
this.eventBus.emit(new RefreshGraphicsEvent());
|
||||
}
|
||||
this.game.recentlyUpdatedTiles().forEach((t) => this.enqueueTile(t));
|
||||
const updates = this.game.updatesSinceLastTick();
|
||||
const unitUpdates = updates !== null ? updates[GameUpdateType.Unit] : [];
|
||||
@@ -464,53 +458,24 @@ export class TerritoryLayer implements Layer {
|
||||
const alternativeColor = this.alternateViewColor(owner);
|
||||
this.paintTile(this.alternativeImageData, tile, alternativeColor, 255);
|
||||
}
|
||||
if (
|
||||
this.game.hasUnitNearby(
|
||||
tile,
|
||||
this.game.config().defensePostRange(),
|
||||
UnitType.DefensePost,
|
||||
owner.id(),
|
||||
)
|
||||
) {
|
||||
const borderColors = this.theme.defendedBorderColors(owner);
|
||||
const x = this.game.x(tile);
|
||||
const y = this.game.y(tile);
|
||||
const lightTile =
|
||||
(x % 2 === 0 && y % 2 === 0) || (y % 2 === 1 && x % 2 === 1);
|
||||
const borderColor = lightTile ? borderColors.light : borderColors.dark;
|
||||
this.paintTile(this.imageData, tile, borderColor, 255);
|
||||
} else {
|
||||
const useBorderColor = playerIsFocused
|
||||
? this.theme.focusedBorderColor()
|
||||
: this.theme.borderColor(owner);
|
||||
this.paintTile(this.imageData, tile, useBorderColor, 255);
|
||||
}
|
||||
} else {
|
||||
// Interior tiles
|
||||
const pattern = owner.cosmetics.pattern;
|
||||
const patternsEnabled = this.cachedTerritoryPatternsEnabled ?? false;
|
||||
const isDefended = this.game.hasUnitNearby(
|
||||
tile,
|
||||
this.game.config().defensePostRange(),
|
||||
UnitType.DefensePost,
|
||||
owner.id(),
|
||||
);
|
||||
|
||||
this.paintTile(
|
||||
this.imageData,
|
||||
tile,
|
||||
owner.borderColor(tile, isDefended),
|
||||
255,
|
||||
);
|
||||
} else {
|
||||
// Alternative view only shows borders.
|
||||
this.clearAlternativeTile(tile);
|
||||
|
||||
if (pattern === undefined || patternsEnabled === false) {
|
||||
this.paintTile(
|
||||
this.imageData,
|
||||
tile,
|
||||
this.theme.territoryColor(owner),
|
||||
150,
|
||||
);
|
||||
} else {
|
||||
const x = this.game.x(tile);
|
||||
const y = this.game.y(tile);
|
||||
const baseColor = this.theme.territoryColor(owner);
|
||||
|
||||
const decoder = owner.patternDecoder();
|
||||
const color = decoder?.isSet(x, y)
|
||||
? baseColor.darken(0.125)
|
||||
: baseColor;
|
||||
this.paintTile(this.imageData, tile, color, 150);
|
||||
}
|
||||
this.paintTile(this.imageData, tile, owner.territoryColor(tile), 150);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ export class UILayer implements Layer {
|
||||
if (this.context === null || this.theme === null) {
|
||||
return;
|
||||
}
|
||||
const color = this.theme.borderColor(unit.owner());
|
||||
const color = unit.owner().borderColor();
|
||||
this.context.fillStyle = color.toRgbString();
|
||||
this.context.fillRect(startX, startY, icon.width, icon.height);
|
||||
this.context.drawImage(icon, startX, startY);
|
||||
@@ -208,7 +208,7 @@ export class UILayer implements Layer {
|
||||
|
||||
// Get the unit's owner color for the box
|
||||
if (this.theme === null) throw new Error("missing theme");
|
||||
const ownerColor = this.theme.territoryColor(unit.owner());
|
||||
const ownerColor = unit.owner().territoryColor();
|
||||
|
||||
// Create a brighter version of the owner color for the selection
|
||||
const selectionColor = ownerColor.lighten(0.2);
|
||||
|
||||
@@ -201,7 +201,7 @@ export class UnitLayer implements Layer {
|
||||
this.game.x(t),
|
||||
this.game.y(t),
|
||||
this.relationship(unit),
|
||||
this.theme.territoryColor(unit.owner()),
|
||||
unit.owner().territoryColor(),
|
||||
150,
|
||||
this.unitTrailContext,
|
||||
);
|
||||
@@ -321,14 +321,14 @@ export class UnitLayer implements Layer {
|
||||
this.game.x(unit.tile()),
|
||||
this.game.y(unit.tile()),
|
||||
rel,
|
||||
this.theme.borderColor(unit.owner()),
|
||||
unit.owner().borderColor(),
|
||||
255,
|
||||
);
|
||||
this.paintCell(
|
||||
this.game.x(unit.lastTile()),
|
||||
this.game.y(unit.lastTile()),
|
||||
rel,
|
||||
this.theme.borderColor(unit.owner()),
|
||||
unit.owner().borderColor(),
|
||||
255,
|
||||
);
|
||||
}
|
||||
@@ -369,7 +369,7 @@ export class UnitLayer implements Layer {
|
||||
this.game.x(t),
|
||||
this.game.y(t),
|
||||
rel,
|
||||
this.theme.territoryColor(other.owner()),
|
||||
other.owner().territoryColor(),
|
||||
150,
|
||||
this.unitTrailContext,
|
||||
);
|
||||
@@ -410,7 +410,7 @@ export class UnitLayer implements Layer {
|
||||
|
||||
this.drawTrail(
|
||||
trail.slice(-newTrailSize),
|
||||
this.theme.territoryColor(unit.owner()),
|
||||
unit.owner().territoryColor(),
|
||||
rel,
|
||||
);
|
||||
this.drawSprite(unit);
|
||||
@@ -430,7 +430,7 @@ export class UnitLayer implements Layer {
|
||||
this.game.x(unit.tile()),
|
||||
this.game.y(unit.tile()),
|
||||
rel,
|
||||
this.theme.borderColor(unit.owner()),
|
||||
unit.owner().borderColor(),
|
||||
255,
|
||||
);
|
||||
}
|
||||
@@ -454,11 +454,7 @@ export class UnitLayer implements Layer {
|
||||
trail.push(unit.lastTile());
|
||||
|
||||
// Paint trail
|
||||
this.drawTrail(
|
||||
trail.slice(-1),
|
||||
this.theme.territoryColor(unit.owner()),
|
||||
rel,
|
||||
);
|
||||
this.drawTrail(trail.slice(-1), unit.owner().territoryColor(), rel);
|
||||
this.drawSprite(unit);
|
||||
|
||||
if (!unit.isActive()) {
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import { LitElement, TemplateResult, html } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import { translateText } from "../../../client/Utils";
|
||||
import { Pattern } from "../../../core/CosmeticSchemas";
|
||||
import { ColorPalette, Pattern } from "../../../core/CosmeticSchemas";
|
||||
import { EventBus } from "../../../core/EventBus";
|
||||
import { GameUpdateType } from "../../../core/game/GameUpdates";
|
||||
import { GameView } from "../../../core/game/GameView";
|
||||
import "../../components/PatternButton";
|
||||
import { fetchPatterns, handlePurchase } from "../../Cosmetics";
|
||||
import {
|
||||
fetchCosmetics,
|
||||
handlePurchase,
|
||||
patternRelationship,
|
||||
} from "../../Cosmetics";
|
||||
import { getUserMe } from "../../jwt";
|
||||
import { SendWinnerEvent } from "../../Transport";
|
||||
import { Layer } from "./Layer";
|
||||
@@ -108,19 +112,41 @@ export class WinModal extends LitElement implements Layer {
|
||||
|
||||
async loadPatternContent() {
|
||||
const me = await getUserMe();
|
||||
const patterns = await fetchPatterns(me !== false ? me : null);
|
||||
const patterns = await fetchCosmetics();
|
||||
|
||||
const purchasable = Array.from(patterns.values()).filter(
|
||||
(p) => p.product !== null,
|
||||
);
|
||||
const purchasablePatterns: {
|
||||
pattern: Pattern;
|
||||
colorPalette: ColorPalette;
|
||||
}[] = [];
|
||||
|
||||
if (purchasable.length === 0) {
|
||||
for (const pattern of Object.values(patterns?.patterns ?? {})) {
|
||||
for (const colorPalette of pattern.colorPalettes ?? []) {
|
||||
if (
|
||||
patternRelationship(
|
||||
pattern,
|
||||
colorPalette,
|
||||
me !== false ? me : null,
|
||||
null,
|
||||
) === "purchasable"
|
||||
) {
|
||||
const palette = patterns?.colorPalettes?.[colorPalette.name];
|
||||
if (palette) {
|
||||
purchasablePatterns.push({
|
||||
pattern,
|
||||
colorPalette: palette,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (purchasablePatterns.length === 0) {
|
||||
this.patternContent = html``;
|
||||
return;
|
||||
}
|
||||
|
||||
// Shuffle the array and take patterns based on screen size
|
||||
const shuffled = [...purchasable].sort(() => Math.random() - 0.5);
|
||||
const shuffled = [...purchasablePatterns].sort(() => Math.random() - 0.5);
|
||||
const isMobile = window.innerWidth < 768; // md breakpoint
|
||||
const maxPatterns = isMobile ? 1 : 3;
|
||||
const selectedPatterns = shuffled.slice(
|
||||
@@ -131,11 +157,14 @@ export class WinModal extends LitElement implements Layer {
|
||||
this.patternContent = html`
|
||||
<div class="flex gap-4 flex-wrap justify-start">
|
||||
${selectedPatterns.map(
|
||||
(pattern) => html`
|
||||
({ pattern, colorPalette }) => html`
|
||||
<pattern-button
|
||||
.pattern=${pattern}
|
||||
.colorPalette=${colorPalette}
|
||||
.requiresPurchase=${true}
|
||||
.onSelect=${(p: Pattern | null) => {}}
|
||||
.onPurchase=${(p: Pattern) => handlePurchase(p)}
|
||||
.onPurchase=${(p: Pattern, colorPalette: ColorPalette | null) =>
|
||||
handlePurchase(p, colorPalette)}
|
||||
></pattern-button>
|
||||
`,
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user