diff --git a/src/client/Main.ts b/src/client/Main.ts index 567a6673b..0d00af662 100644 --- a/src/client/Main.ts +++ b/src/client/Main.ts @@ -21,6 +21,8 @@ import { LangSelector } from "./LangSelector"; import { LanguageModal } from "./LanguageModal"; import "./PublicLobby"; import { PublicLobby } from "./PublicLobby"; +import "./RandomNameButton"; +import { RandomNameButton } from "./RandomNameButton"; import { SinglePlayerModal } from "./SinglePlayerModal"; import { UserSettingModal } from "./UserSettingModal"; import "./UsernameInput"; @@ -46,6 +48,7 @@ class Client { private usernameInput: UsernameInput | null = null; private flagInput: FlagInput | null = null; private darkModeButton: DarkModeButton | null = null; + private randomNameButton: RandomNameButton | null = null; private joinModal: JoinPrivateLobbyModal; private publicLobby: PublicLobby; @@ -80,6 +83,13 @@ class Client { consolex.warn("Dark mode button element not found"); } + this.randomNameButton = document.querySelector( + "random-name-button", + ) as RandomNameButton; + if (!this.randomNameButton) { + consolex.warn("Random name button element not found"); + } + this.usernameInput = document.querySelector( "username-input", ) as UsernameInput; diff --git a/src/client/RandomNameButton.ts b/src/client/RandomNameButton.ts new file mode 100644 index 000000000..4617c784f --- /dev/null +++ b/src/client/RandomNameButton.ts @@ -0,0 +1,30 @@ +import { LitElement, html } from "lit"; +import { customElement, state } from "lit/decorators.js"; +import { UserSettings } from "../core/game/UserSettings"; + +@customElement("random-name-button") +export class RandomNameButton extends LitElement { + private userSettings: UserSettings = new UserSettings(); + @state() private randomName: boolean = this.userSettings.anonymousNames(); + + createRenderRoot() { + return this; + } + + toggleRandomName() { + this.userSettings.toggleRandomName(); + this.randomName = this.userSettings.anonymousNames(); + } + + render() { + return html` + + `; + } +} diff --git a/src/client/graphics/layers/NameLayer.ts b/src/client/graphics/layers/NameLayer.ts index 6166c1d76..1ecdfba02 100644 --- a/src/client/graphics/layers/NameLayer.ts +++ b/src/client/graphics/layers/NameLayer.ts @@ -195,6 +195,7 @@ export class NameLayer implements Layer { nameDiv.style.alignItems = "center"; const nameSpan = document.createElement("span"); + nameSpan.className = "player-name-span"; nameSpan.innerHTML = player.name(); nameDiv.appendChild(nameSpan); element.appendChild(nameDiv); @@ -262,6 +263,10 @@ export class NameLayer implements Layer { nameDiv.style.fontSize = `${render.fontSize}px`; nameDiv.style.lineHeight = `${render.fontSize}px`; nameDiv.style.color = render.fontColor; + const span = nameDiv.querySelector(".player-name-span"); + if (span) { + span.innerHTML = render.player.name(); + } if (flagDiv) { flagDiv.style.height = `${render.fontSize}px`; } diff --git a/src/client/graphics/layers/OptionsMenu.ts b/src/client/graphics/layers/OptionsMenu.ts index 165c99afd..cad75e929 100644 --- a/src/client/graphics/layers/OptionsMenu.ts +++ b/src/client/graphics/layers/OptionsMenu.ts @@ -106,6 +106,10 @@ export class OptionsMenu extends LitElement implements Layer { this.eventBus.emit(new RefreshGraphicsEvent()); } + private onToggleRandomNameModeButtonClick() { + this.userSettings.toggleRandomName(); + } + private onToggleFocusLockedButtonClick() { this.userSettings.toggleFocusLocked(); this.requestUpdate(); @@ -196,6 +200,12 @@ export class OptionsMenu extends LitElement implements Layer { title: "Dark Mode", children: "🌙: " + (this.userSettings.darkMode() ? "On" : "Off"), })} + ${button({ + onClick: this.onToggleRandomNameModeButtonClick, + title: "Random name mode", + children: + "🥷: " + (this.userSettings.anonymousNames() ? "On" : "Off"), + })} ${button({ onClick: this.onToggleLeftClickOpensMenu, title: "Left click", diff --git a/src/client/index.html b/src/client/index.html index f6669b532..ba6a0f4a4 100644 --- a/src/client/index.html +++ b/src/client/index.html @@ -208,6 +208,9 @@
+ + +
diff --git a/src/core/Util.ts b/src/core/Util.ts index 62304353c..489d53bb1 100644 --- a/src/core/Util.ts +++ b/src/core/Util.ts @@ -13,6 +13,11 @@ import { Turn, } from "./Schemas"; +import { + BOT_NAME_PREFIXES, + BOT_NAME_SUFFIXES, +} from "./execution/utils/BotNames"; + export function manhattanDistWrapped( c1: Cell, c2: Cell, @@ -286,3 +291,19 @@ export function withinInt(num: bigint, min: bigint, max: bigint): bigint { const atLeastMin = maxInt(num, min); return minInt(atLeastMin, max); } + +export function createRandomName( + name: string, + playerType: string, +): string | null { + let randomName = null; + if (playerType === "HUMAN") { + const hash = simpleHash(name); + const prefixIndex = hash % BOT_NAME_PREFIXES.length; + const suffixIndex = + Math.floor(hash / BOT_NAME_PREFIXES.length) % BOT_NAME_SUFFIXES.length; + + randomName = `👤 ${BOT_NAME_PREFIXES[prefixIndex]} ${BOT_NAME_SUFFIXES[suffixIndex]}`; + } + return randomName; +} diff --git a/src/core/game/GameView.ts b/src/core/game/GameView.ts index 3f7d9bf5e..877ec19cf 100644 --- a/src/core/game/GameView.ts +++ b/src/core/game/GameView.ts @@ -1,5 +1,6 @@ import { Config } from "../configuration/Config"; import { ClientID, GameID, PlayerStats } from "../Schemas"; +import { createRandomName } from "../Util"; import { WorkerClient } from "../worker/WorkerClient"; import { Cell, @@ -123,11 +124,22 @@ export class UnitView { } export class PlayerView { + public anonymousName: string; + constructor( private game: GameView, public data: PlayerUpdate, public nameData: NameViewData, - ) {} + ) { + if (data.clientID == game.myClientID()) { + this.anonymousName = this.data.name; + } else { + this.anonymousName = createRandomName( + this.data.name, + this.data.playerType, + ); + } + } async actions(tile: TileRef): Promise { return this.game.worker.playerInteraction( @@ -166,11 +178,16 @@ export class PlayerView { return this.data.flag; } name(): string { - return this.data.name; + return userSettings.anonymousNames() && this.anonymousName !== null + ? this.anonymousName + : this.data.name; } displayName(): string { - return this.data.displayName; + return userSettings.anonymousNames() && this.anonymousName !== null + ? this.anonymousName + : this.data.name; } + clientID(): ClientID { return this.data.clientID; } diff --git a/src/core/game/UserSettings.ts b/src/core/game/UserSettings.ts index 3c22c8ac5..f6049ce7a 100644 --- a/src/core/game/UserSettings.ts +++ b/src/core/game/UserSettings.ts @@ -15,6 +15,9 @@ export class UserSettings { emojis() { return this.get("settings.emojis", true); } + anonymousNames() { + return this.get("settings.anonymousNames", false); + } darkMode() { return this.get("settings.darkMode", false); @@ -42,6 +45,10 @@ export class UserSettings { this.set("settings.emojis", !this.emojis()); } + toggleRandomName() { + this.set("settings.anonymousNames", !this.anonymousNames()); + } + toggleDarkMode() { this.set("settings.darkMode", !this.darkMode()); if (this.darkMode()) {