Add Alt + Click hotkey for sending emotes (#408)

## Description:

Allows the player to Alt + Click to send emotes to other players or
themself in order to ease communication.
Of course, the hotkey can be something different. Alt + Click is just a
suggestion.


![image](https://github.com/user-attachments/assets/9762c4f0-f62d-4c39-ba35-468ac3f5ddaa)

## Please complete the following:

- [ x ] I have added screenshots for all UI updates
- [ x ] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [ x ] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors

## Please put your Discord username so you can be contacted if a bug or
regression is found:

kanekane0448

PS: The new emoji table looks really good!

---------

Co-authored-by: kanekane0448 <no@mail.pls>
This commit is contained in:
kanekane0448
2025-04-04 19:15:59 +02:00
committed by GitHub
parent 924ca2c69e
commit a97a608dce
6 changed files with 62 additions and 2 deletions
+1
View File
@@ -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",
+4
View File
@@ -46,6 +46,10 @@ export class HelpModal extends LitElement {
<td>Ctrl + left click</td>
<td>${translateText("help_modal.action_build")}</td>
</tr>
<tr>
<td>Alt + left click</td>
<td>${translateText("help_modal.action_emote")}</td>
</tr>
<tr>
<td>C</td>
<td>${translateText("help_modal.action_center")}</td>
+10
View File
@@ -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) +
+1 -1
View File
@@ -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 {
+6 -1
View File
@@ -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");
+40
View File
@@ -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() {