diff --git a/resources/lang/en.json b/resources/lang/en.json index cedf01779..024878fad 100644 --- a/resources/lang/en.json +++ b/resources/lang/en.json @@ -22,6 +22,7 @@ "action_alt_view": "Alternate view (terrain/countries)", "action_attack_altclick": "Attack (when left click is set to open menu)", "action_build": "Open build menu", + "action_emote": "Open emote menu", "action_center": "Center camera on player", "action_zoom": "Zoom out/in", "action_move_camera": "Move camera", diff --git a/src/client/HelpModal.ts b/src/client/HelpModal.ts index bbf842eb9..8de819377 100644 --- a/src/client/HelpModal.ts +++ b/src/client/HelpModal.ts @@ -46,6 +46,10 @@ export class HelpModal extends LitElement { Ctrl + left click ${translateText("help_modal.action_build")} + + Alt + left click + ${translateText("help_modal.action_emote")} + C ${translateText("help_modal.action_center")} diff --git a/src/client/InputHandler.ts b/src/client/InputHandler.ts index 806bc6cf8..ae495e9fe 100644 --- a/src/client/InputHandler.ts +++ b/src/client/InputHandler.ts @@ -69,6 +69,12 @@ export class ShowBuildMenuEvent implements GameEvent { public readonly y: number, ) {} } +export class ShowEmojiMenuEvent implements GameEvent { + constructor( + public readonly x: number, + public readonly y: number, + ) {} +} export class AttackRatioEvent implements GameEvent { constructor(public readonly attackRatio: number) {} @@ -292,6 +298,10 @@ export class InputHandler { this.eventBus.emit(new ShowBuildMenuEvent(event.clientX, event.clientY)); return; } + if (event.altKey) { + this.eventBus.emit(new ShowEmojiMenuEvent(event.clientX, event.clientY)); + return; + } const dist = Math.abs(event.x - this.lastPointerDownX) + diff --git a/src/client/Main.ts b/src/client/Main.ts index 6b4b623c9..e2637e4ae 100644 --- a/src/client/Main.ts +++ b/src/client/Main.ts @@ -10,7 +10,6 @@ import "./DarkModeButton"; import { DarkModeButton } from "./DarkModeButton"; import "./FlagInput"; import { FlagInput } from "./FlagInput"; -import { GameStartingModal } from "./GameStartingModal"; import "./GoogleAdElement"; import GoogleAdElement from "./GoogleAdElement"; import { HelpModal } from "./HelpModal"; @@ -27,6 +26,7 @@ import { UsernameInput } from "./UsernameInput"; import { generateCryptoRandomUUID } from "./Utils"; import "./components/baseComponents/Button"; import "./components/baseComponents/Modal"; +import { GameStartingModal } from "./gameStartingModal"; import "./styles.css"; export interface JoinLobbyEvent { diff --git a/src/client/graphics/GameRenderer.ts b/src/client/graphics/GameRenderer.ts index 5f76b79e7..9207067b4 100644 --- a/src/client/graphics/GameRenderer.ts +++ b/src/client/graphics/GameRenderer.ts @@ -2,8 +2,8 @@ import { consolex } from "../../core/Consolex"; import { EventBus } from "../../core/EventBus"; import { ClientID } from "../../core/Schemas"; import { GameView } from "../../core/game/GameView"; -import { GameStartingModal } from "../GameStartingModal"; import { RefreshGraphicsEvent as RedrawGraphicsEvent } from "../InputHandler"; +import { GameStartingModal } from "../gameStartingModal"; import { TransformHandler } from "./TransformHandler"; import { UIState } from "./UIState"; import { BuildMenu } from "./layers/BuildMenu"; @@ -47,6 +47,11 @@ export function createRenderer( if (!emojiTable || !(emojiTable instanceof EmojiTable)) { consolex.error("EmojiTable element not found in the DOM"); } + emojiTable.eventBus = eventBus; + emojiTable.transformHandler = transformHandler; + emojiTable.game = game; + emojiTable.initEventBus(); + const buildMenu = document.querySelector("build-menu") as BuildMenu; if (!buildMenu || !(buildMenu instanceof BuildMenu)) { consolex.error("BuildMenu element not found in the DOM"); diff --git a/src/client/graphics/layers/EmojiTable.ts b/src/client/graphics/layers/EmojiTable.ts index 06edeecb0..5db92c866 100644 --- a/src/client/graphics/layers/EmojiTable.ts +++ b/src/client/graphics/layers/EmojiTable.ts @@ -1,5 +1,12 @@ import { LitElement, css, html } from "lit"; import { customElement, state } from "lit/decorators.js"; +import { EventBus } from "../../../core/EventBus"; +import { AllPlayers } from "../../../core/game/Game"; +import { GameView, PlayerView } from "../../../core/game/GameView"; +import { TerraNulliusImpl } from "../../../core/game/TerraNulliusImpl"; +import { ShowEmojiMenuEvent } from "../../InputHandler"; +import { SendEmojiIntentEvent } from "../../Transport"; +import { TransformHandler } from "../TransformHandler"; const emojiTable: string[][] = [ ["😀", "😊", "🥰", "😇", "😎"], @@ -17,6 +24,10 @@ const emojiTable: string[][] = [ @customElement("emoji-table") export class EmojiTable extends LitElement { + public eventBus: EventBus; + public transformHandler: TransformHandler; + public game: GameView; + static styles = css` :host { display: block; @@ -96,6 +107,35 @@ export class EmojiTable extends LitElement { @state() private _hidden = true; + initEventBus() { + this.eventBus.on(ShowEmojiMenuEvent, (e) => { + const cell = this.transformHandler.screenToWorldCoordinates(e.x, e.y); + if (!this.game.isValidCoord(cell.x, cell.y)) { + return; + } + + const tile = this.game.ref(cell.x, cell.y); + if (!this.game.hasOwner(tile)) { + return; + } + + const targetPlayer = this.game.owner(tile); + // maybe redundant due to owner check but better safe than sorry + if (targetPlayer instanceof TerraNulliusImpl) { + return; + } + + this.showTable((emoji) => { + const recipient = + targetPlayer == this.game.myPlayer() + ? AllPlayers + : (targetPlayer as PlayerView); + this.eventBus.emit(new SendEmojiIntentEvent(recipient, emoji)); + this.hideTable(); + }); + }); + } + private onEmojiClicked: (emoji: string) => void = () => {}; render() {