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() {