diff --git a/resources/lang/en.json b/resources/lang/en.json index 1e7c2d6b73..408203aea3 100644 --- a/resources/lang/en.json +++ b/resources/lang/en.json @@ -477,6 +477,8 @@ "tab_keybinds": "Keybinds", "dark_mode_label": "Dark Mode", "dark_mode_desc": "Toggle the siteβs appearance between light and dark themes", + "color_blind_label": "Color-blind assist", + "color_blind_desc": "Adds visual aid to make spotting teammates during spawn phase easier", "emojis_label": "Emojis", "emojis_desc": "Toggle whether emojis are shown in game", "alert_frame_label": "Alert Frame", diff --git a/src/client/UserSettingModal.ts b/src/client/UserSettingModal.ts index 70f4251f80..5206505e6d 100644 --- a/src/client/UserSettingModal.ts +++ b/src/client/UserSettingModal.ts @@ -279,6 +279,14 @@ export class UserSettingModal extends BaseModal { console.log("π Dark Mode:", enabled ? "ON" : "OFF"); } + private toggleColorBlind(e: CustomEvent<{ checked: boolean }>) { + const enabled = e.detail?.checked; + if (typeof enabled !== "boolean") return; + + this.userSettings.set("settings.colorBlind", enabled); + this.requestUpdate(); + } + private toggleEmojis(e: CustomEvent<{ checked: boolean }>) { const enabled = e.detail?.checked; if (typeof enabled !== "boolean") return; @@ -794,6 +802,15 @@ export class UserSettingModal extends BaseModal { this.toggleDarkMode(e)} > + + + + + + + + ${translateText("user_setting.color_blind_label")} + + + ${translateText("user_setting.color_blind_desc")} + + + + ${this.userSettings.colorBlind() + ? translateText("user_setting.on") + : translateText("user_setting.off")} + + + p !== myPlayer && myPlayer.isOnSameTeam(p)); - - // Smaller radius for teammates (more subtle than self highlight) - const teammateMinRad = 5; - const teammateMaxRad = 14; - const teammateRadius = - teammateMinRad + - (teammateMaxRad - teammateMinRad) * - ((radius - minRad) / (maxRad - minRad)); - - const teamColors = Object.values(ColoredTeams); - for (const teammate of teammates) { - const center = teammate.nameLocation(); - if (!center) { - continue; - } - - const team = teammate.team(); - let baseColor: Colord; - let breathingColor: Colord; - - if (team !== null && teamColors.includes(team)) { - baseColor = this.theme.teamColor(team).alpha(0.5); - breathingColor = this.theme.teamColor(team).alpha(0.5); - } else { - baseColor = this.theme.spawnHighlightTeamColor(); - breathingColor = this.theme.spawnHighlightTeamColor(); - } - - this.drawBreathingRing( - center.x, - center.y, - teammateMinRad, - teammateMaxRad, - teammateRadius, - baseColor, - breathingColor, - ); + const spawnTile = player.spawnTile(); + if (spawnTile === undefined) { + return; } + drawTeammateGlow( + this.highlightContext, + this.game.x(spawnTile), + this.game.y(spawnTile), + { + outerRadius: TerritoryLayer.SPAWN_HIGHLIGHT_RADIUS - 1, + pulsePhase: this.game.ticks() * TerritoryLayer.PULSE_SPEED, + }, + ); } init() { diff --git a/src/core/game/GameUpdates.ts b/src/core/game/GameUpdates.ts index b8786e14b9..52c839da93 100644 --- a/src/core/game/GameUpdates.ts +++ b/src/core/game/GameUpdates.ts @@ -176,6 +176,7 @@ export interface PlayerUpdate { outgoingAllianceRequests: PlayerID[]; alliances: AllianceView[]; hasSpawned: boolean; + spawnTile?: TileRef; betrayals: number; lastDeleteUnitTick: Tick; isLobbyCreator: boolean; diff --git a/src/core/game/GameView.ts b/src/core/game/GameView.ts index 15ce0d5648..8e6bf3264d 100644 --- a/src/core/game/GameView.ts +++ b/src/core/game/GameView.ts @@ -562,6 +562,9 @@ export class PlayerView { hasSpawned(): boolean { return this.data.hasSpawned; } + spawnTile(): TileRef | undefined { + return this.data.spawnTile; + } isDisconnected(): boolean { return this.data.isDisconnected; } diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index dd72a33075..65b1debecc 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -179,6 +179,7 @@ export class PlayerImpl implements Player { }) satisfies AllianceView, ), hasSpawned: this.hasSpawned(), + spawnTile: this.spawnTile(), betrayals: this._betrayalCount, lastDeleteUnitTick: this.lastDeleteUnitTick, isLobbyCreator: this.isLobbyCreator(), diff --git a/src/core/game/UserSettings.ts b/src/core/game/UserSettings.ts index ba74b9ae8c..88a47e4279 100644 --- a/src/core/game/UserSettings.ts +++ b/src/core/game/UserSettings.ts @@ -73,6 +73,10 @@ export class UserSettings { return this.get("settings.territoryPatterns", true); } + colorBlind() { + return this.get("settings.colorBlind", false); + } + cursorCostLabel() { const legacy = this.get("settings.ghostPricePill", true); return this.get("settings.cursorCostLabel", legacy); @@ -128,6 +132,10 @@ export class UserSettings { this.set("settings.territoryPatterns", !this.territoryPatterns()); } + toggleColorBlind() { + this.set("settings.colorBlind", !this.colorBlind()); + } + toggleDarkMode() { this.set("settings.darkMode", !this.darkMode()); if (this.darkMode()) {