From 08e1a7acf77e5300d77100680d1bdd90c784d075 Mon Sep 17 00:00:00 2001 From: NewHappyRabbit <31893343+NewHappyRabbit@users.noreply.github.com> Date: Thu, 13 Feb 2025 21:27:52 +0200 Subject: [PATCH] Player can now disable emojis --- src/client/ClientGameRunner.ts | 15 +++- src/client/graphics/layers/NameLayer.ts | 2 +- src/client/graphics/layers/OptionsMenu.ts | 102 ++++++++++++++++------ src/client/index.html | 4 +- src/core/GameRunner.ts | 4 +- src/core/configuration/Config.ts | 11 ++- src/core/configuration/DefaultConfig.ts | 6 ++ src/core/configuration/DevConfig.ts | 5 +- src/core/game/UserSettings.ts | 30 +++++++ 9 files changed, 141 insertions(+), 38 deletions(-) create mode 100644 src/core/game/UserSettings.ts diff --git a/src/client/ClientGameRunner.ts b/src/client/ClientGameRunner.ts index 9b225c143..7c34dcb5d 100644 --- a/src/client/ClientGameRunner.ts +++ b/src/client/ClientGameRunner.ts @@ -46,6 +46,7 @@ import { consolex, initRemoteSender } from "../core/Consolex"; import { getConfig, getServerConfig } from "../core/configuration/Config"; import { GameView, PlayerView } from "../core/game/GameView"; import { GameUpdateViewData } from "../core/game/GameUpdates"; +import { UserSettings } from "../core/game/UserSettings"; export interface LobbyConfig { flag: () => string; @@ -75,6 +76,7 @@ export function joinLobby( const serverConfig = getServerConfig(); + const userSettings: UserSettings = new UserSettings(); let gameConfig: GameConfig = null; if (lobbyConfig.gameType == GameType.Singleplayer) { gameConfig = { @@ -102,9 +104,13 @@ export function joinLobby( if (message.type == "start") { consolex.log("lobby: game started"); onjoin(); - createClientGame(lobbyConfig, message.config, eventBus, transport).then( - (r) => r.start(), - ); + createClientGame( + lobbyConfig, + message.config, + eventBus, + transport, + userSettings, + ).then((r) => r.start()); } }; transport.connect(onconnect, onmessage); @@ -119,8 +125,9 @@ export async function createClientGame( gameConfig: GameConfig, eventBus: EventBus, transport: Transport, + userSettings: UserSettings, ): Promise { - const config = getConfig(gameConfig); + const config = getConfig(gameConfig, userSettings); const gameMap = await loadTerrainMap(gameConfig.gameMap); const worker = new WorkerClient( diff --git a/src/client/graphics/layers/NameLayer.ts b/src/client/graphics/layers/NameLayer.ts index 66a66ab82..86f499be1 100644 --- a/src/client/graphics/layers/NameLayer.ts +++ b/src/client/graphics/layers/NameLayer.ts @@ -322,7 +322,7 @@ export class NameLayer implements Layer { emoji.recipientID == myPlayer?.smallID(), ); - if (emojis.length > 0) { + if (this.game.config().userSettings().emojis() && emojis.length > 0) { if (!existingEmoji) { const emojiDiv = document.createElement("div"); emojiDiv.setAttribute("data-icon", "emoji"); diff --git a/src/client/graphics/layers/OptionsMenu.ts b/src/client/graphics/layers/OptionsMenu.ts index b52f2f53d..38c28af25 100644 --- a/src/client/graphics/layers/OptionsMenu.ts +++ b/src/client/graphics/layers/OptionsMenu.ts @@ -6,11 +6,34 @@ import { GameType } from "../../../core/game/Game"; import { GameView } from "../../../core/game/GameView"; import { Layer } from "./Layer"; import { GameUpdateType } from "../../../core/game/GameUpdates"; +import { UserSettings } from "../../../core/game/UserSettings"; + +const button = ({ + classes = "", + onClick = () => {}, + title = "", + children, +}) => html` + +`; @customElement("options-menu") export class OptionsMenu extends LitElement implements Layer { public game: GameView; public eventBus: EventBus; + private userSettings: UserSettings = new UserSettings(); @state() private showPauseButton: boolean = true; @@ -21,6 +44,9 @@ export class OptionsMenu extends LitElement implements Layer { @state() private timer: number = 0; + @state() + private showSettings: boolean = false; + private isVisible = false; private hasWinner = false; @@ -33,11 +59,26 @@ export class OptionsMenu extends LitElement implements Layer { return this; } + private onSettingsButtonClick() { + this.showSettings = !this.showSettings; + this.requestUpdate(); + } + private onPauseButtonClick() { this.isPaused = !this.isPaused; this.eventBus.emit(new PauseGameEvent(this.isPaused)); } + private onToggleEmojisButtonClick() { + this.userSettings.toggleEmojis(); + this.requestUpdate(); + } + + private onToggleDarkModeButtonClick() { + this.userSettings.toggleDarkMode(); + this.requestUpdate(); + } + init() { console.log("init called from OptionsMenu"); this.showPauseButton = @@ -71,20 +112,13 @@ export class OptionsMenu extends LitElement implements Layer {
-
- +
+ ${button({ + classes: !this.showPauseButton ? "hidden" : "", + onClick: this.onPauseButtonClick, + title: this.isPaused ? "Resume game" : "Pause game", + children: this.isPaused ? "▶️" : "⏸", + })}
- × - + ${button({ + onClick: this.onExitButtonClick, + title: "Exit game", + children: "❌", + })} + ${button({ + onClick: this.onSettingsButtonClick, + title: "Settings", + children: "⚙️", + })}
+ +
+ ${button({ + onClick: this.onToggleEmojisButtonClick, + title: "Toggle Emojis", + children: "🙂: " + (this.userSettings.emojis() ? "On" : "Off"), + })} + +
`; } diff --git a/src/client/index.html b/src/client/index.html index 707780ef4..f8d0adc76 100644 --- a/src/client/index.html +++ b/src/client/index.html @@ -210,7 +210,9 @@ -
+
diff --git a/src/core/GameRunner.ts b/src/core/GameRunner.ts index 8a95ee462..78950874e 100644 --- a/src/core/GameRunner.ts +++ b/src/core/GameRunner.ts @@ -24,6 +24,7 @@ import { createGame } from "./game/GameImpl"; import { loadTerrainMap as loadGameMap } from "./game/TerrainMapLoader"; import { ClientID, GameConfig, Turn } from "./Schemas"; import { GameUpdateViewData } from "./game/GameUpdates"; +import { UserSettings } from "./game/UserSettings"; export async function createGameRunner( gameID: string, @@ -31,7 +32,8 @@ export async function createGameRunner( clientID: ClientID, callBack: (gu: GameUpdateViewData) => void, ): Promise { - const config = getConfig(gameConfig); + const userSettings: UserSettings = new UserSettings(); + const config = getConfig(gameConfig, userSettings); const gameMap = await loadGameMap(gameConfig.gameMap); const game = createGame( gameMap.gameMap, diff --git a/src/core/configuration/Config.ts b/src/core/configuration/Config.ts index 0d2dc1c51..37306bd26 100644 --- a/src/core/configuration/Config.ts +++ b/src/core/configuration/Config.ts @@ -20,20 +20,24 @@ import { DefaultConfig } from "./DefaultConfig"; import { DevConfig, DevServerConfig } from "./DevConfig"; import { GameMap, TileRef } from "../game/GameMap"; import { PlayerView } from "../game/GameView"; +import { UserSettings } from "../game/UserSettings"; export enum GameEnv { Dev, Prod, } -export function getConfig(gameConfig: GameConfig): Config { +export function getConfig( + gameConfig: GameConfig, + userSettings: UserSettings, +): Config { const sc = getServerConfig(); switch (process.env.GAME_ENV) { case "dev": - return new DevConfig(sc, gameConfig); + return new DevConfig(sc, gameConfig, userSettings); case "preprod": case "prod": consolex.log("using prod config"); - return new DefaultConfig(sc, gameConfig); + return new DefaultConfig(sc, gameConfig, userSettings); default: throw Error(`unsupported server configuration: ${process.env.GAME_ENV}`); } @@ -73,6 +77,7 @@ export interface Config { spawnBots(): boolean; creativeMode(): boolean; numSpawnPhaseTurns(): number; + userSettings(): UserSettings; startManpower(playerInfo: PlayerInfo): number; populationIncreaseRate(player: Player | PlayerView): number; diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index 2c21ee40a..6a99c884a 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -14,6 +14,7 @@ import { } from "../game/Game"; import { GameMap, TileRef } from "../game/GameMap"; import { PlayerView } from "../game/GameView"; +import { UserSettings } from "../game/UserSettings"; import { GameConfig } from "../Schemas"; import { assertNever, within } from "../Util"; import { Config, ServerConfig, Theme } from "./Config"; @@ -35,6 +36,7 @@ export class DefaultConfig implements Config { constructor( private _serverConfig: ServerConfig, private _gameConfig: GameConfig, + private _userSettings: UserSettings, ) {} spawnImmunityDuration(): Tick { return 5 * 10; @@ -48,6 +50,10 @@ export class DefaultConfig implements Config { return this._serverConfig; } + userSettings(): UserSettings { + return this._userSettings; + } + difficultyModifier(difficulty: Difficulty): number { switch (difficulty) { case Difficulty.Easy: diff --git a/src/core/configuration/DevConfig.ts b/src/core/configuration/DevConfig.ts index 56d2bf27c..03edb8b8b 100644 --- a/src/core/configuration/DevConfig.ts +++ b/src/core/configuration/DevConfig.ts @@ -1,4 +1,5 @@ import { GameType, Player, PlayerInfo, UnitInfo, UnitType } from "../game/Game"; +import { UserSettings } from "../game/UserSettings"; import { GameConfig } from "../Schemas"; import { ServerConfig } from "./Config"; import { DefaultConfig, DefaultServerConfig } from "./DefaultConfig"; @@ -13,8 +14,8 @@ export class DevServerConfig extends DefaultServerConfig { } export class DevConfig extends DefaultConfig { - constructor(sc: ServerConfig, gc: GameConfig) { - super(sc, gc); + constructor(sc: ServerConfig, gc: GameConfig, us: UserSettings) { + super(sc, gc, us); } numSpawnPhaseTurns(): number { diff --git a/src/core/game/UserSettings.ts b/src/core/game/UserSettings.ts new file mode 100644 index 000000000..5c53987ed --- /dev/null +++ b/src/core/game/UserSettings.ts @@ -0,0 +1,30 @@ +export class UserSettings { + get(key: string, defaultValue: boolean) { + const value = localStorage.getItem(key); + if (!value) return defaultValue; + + if (value === "true") return true; + + if (value === "false") return false; + } + + set(key: string, value: boolean) { + localStorage.setItem(key, value ? "true" : "false"); + } + + emojis() { + return this.get("settings.emojis", true); + } + + darkMode() { + return this.get("settings.darkMode", false); + } + + toggleEmojis() { + this.set("settings.emojis", !this.emojis()); + } + + toggleDarkMode() { + this.set("settings.darkMode", !this.darkMode()); + } +}