From 81bd98c8d68db817a7d6d7319d86f46d5108e993 Mon Sep 17 00:00:00 2001 From: Scott Anderson <662325+scottanderson@users.noreply.github.com> Date: Tue, 26 Aug 2025 17:57:40 -0400 Subject: [PATCH] Nations send emoji when declining assistance requests (#1911) Nations will now send emoji when declining assistance requests. - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced Cancel alliance requests if the recipient attacks (#1733) Problem: attacking a player right before accepting an alliance request is very effective since the requester can't fight back or reclaim his territory without canceling the alliance and being penalized with the traitor debuff. Change: - Attacking a player after he requested an alliance automatically rejects the request - No changes to existing attacks in both directions, only new attacks affect the request - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I have read and accepted the CLA agreement (only required once). regression is found: IngloriousTom --- src/client/graphics/layers/EmojiTable.ts | 4 +- src/client/graphics/layers/PlayerPanel.ts | 9 +++-- .../graphics/layers/RadialMenuElements.ts | 4 +- src/core/Util.ts | 9 +++-- src/core/execution/FakeHumanExecution.ts | 16 ++++---- src/core/execution/utils/BotBehavior.ts | 38 +++++++++++++++---- 6 files changed, 53 insertions(+), 27 deletions(-) diff --git a/src/client/graphics/layers/EmojiTable.ts b/src/client/graphics/layers/EmojiTable.ts index aefec7ade..ca87f009b 100644 --- a/src/client/graphics/layers/EmojiTable.ts +++ b/src/client/graphics/layers/EmojiTable.ts @@ -4,7 +4,7 @@ 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 { emojiTable, flattenedEmojiTable } from "../../../core/Util"; +import { Emoji, emojiTable, flattenedEmojiTable } from "../../../core/Util"; import { CloseViewEvent, ShowEmojiMenuEvent } from "../../InputHandler"; import { SendEmojiIntentEvent } from "../../Transport"; import { TransformHandler } from "../TransformHandler"; @@ -42,7 +42,7 @@ export class EmojiTable extends LitElement { eventBus.emit( new SendEmojiIntentEvent( recipient, - flattenedEmojiTable.indexOf(emoji), + flattenedEmojiTable.indexOf(emoji as Emoji), ), ); this.hideTable(); diff --git a/src/client/graphics/layers/PlayerPanel.ts b/src/client/graphics/layers/PlayerPanel.ts index 65d4bebf1..d3c03bc48 100644 --- a/src/client/graphics/layers/PlayerPanel.ts +++ b/src/client/graphics/layers/PlayerPanel.ts @@ -20,7 +20,7 @@ import { } from "../../../core/game/Game"; import { TileRef } from "../../../core/game/GameMap"; import { GameView, PlayerView } from "../../../core/game/GameView"; -import { flattenedEmojiTable } from "../../../core/Util"; +import { Emoji, flattenedEmojiTable } from "../../../core/Util"; import { actionButton } from "../../components/ui/ActionButton"; import "../../components/ui/Divider"; import Countries from "../../data/countries.json"; @@ -218,12 +218,15 @@ export class PlayerPanel extends LitElement implements Layer { this.eventBus.emit( new SendEmojiIntentEvent( AllPlayers, - flattenedEmojiTable.indexOf(emoji), + flattenedEmojiTable.indexOf(emoji as Emoji), ), ); } else { this.eventBus.emit( - new SendEmojiIntentEvent(other, flattenedEmojiTable.indexOf(emoji)), + new SendEmojiIntentEvent( + other, + flattenedEmojiTable.indexOf(emoji as Emoji), + ), ); } this.emojiTable.hideTable(); diff --git a/src/client/graphics/layers/RadialMenuElements.ts b/src/client/graphics/layers/RadialMenuElements.ts index df95334d8..9e1fe21ef 100644 --- a/src/client/graphics/layers/RadialMenuElements.ts +++ b/src/client/graphics/layers/RadialMenuElements.ts @@ -2,7 +2,7 @@ import { Config } from "../../../core/configuration/Config"; import { AllPlayers, PlayerActions, UnitType } from "../../../core/game/Game"; import { TileRef } from "../../../core/game/GameMap"; import { GameView, PlayerView } from "../../../core/game/GameView"; -import { flattenedEmojiTable } from "../../../core/Util"; +import { Emoji, flattenedEmojiTable } from "../../../core/Util"; import { renderNumber, translateText } from "../../Utils"; import { BuildItemDisplay, BuildMenu, flattenedBuildTable } from "./BuildMenu"; import { ChatIntegration } from "./ChatIntegration"; @@ -271,7 +271,7 @@ const infoEmojiElement: MenuElement = { : params.selected; params.playerActionHandler.handleEmoji( targetPlayer!, - flattenedEmojiTable.indexOf(emoji), + flattenedEmojiTable.indexOf(emoji as Emoji), ); params.emojiTable.hideTable(); }); diff --git a/src/core/Util.ts b/src/core/Util.ts index 8d30c1a23..c16ecd465 100644 --- a/src/core/Util.ts +++ b/src/core/Util.ts @@ -257,7 +257,7 @@ export function createRandomName( return randomName; } -export const emojiTable: string[][] = [ +export const emojiTable = [ ["😀", "😊", "🥰", "😇", "😎"], ["😞", "🥺", "😭", "😱", "😡"], ["😈", "🤡", "🖕", "🥱", "🤦‍♂️"], @@ -269,9 +269,12 @@ export const emojiTable: string[][] = [ ["⬅️", "🎯", "➡️", "🥈", "🥉"], ["↙️", "⬇️", "↘️", "❤️", "💔"], ["💰", "⚓", "⛵", "🏡", "🛡️"], -]; +] as const; + +export type Emoji = (typeof emojiTable)[number][number]; + // 2d to 1d array -export const flattenedEmojiTable: string[] = emojiTable.flat(); +export const flattenedEmojiTable = emojiTable.flat(); /** * JSON.stringify replacer function that converts bigint values to strings. diff --git a/src/core/execution/FakeHumanExecution.ts b/src/core/execution/FakeHumanExecution.ts index bae5b3690..344ec0866 100644 --- a/src/core/execution/FakeHumanExecution.ts +++ b/src/core/execution/FakeHumanExecution.ts @@ -14,10 +14,10 @@ import { Unit, UnitType, } from "../game/Game"; -import { euclDistFN, manhattanDistFN, TileRef } from "../game/GameMap"; +import { TileRef, euclDistFN, manhattanDistFN } from "../game/GameMap"; import { PseudoRandom } from "../PseudoRandom"; import { GameID } from "../Schemas"; -import { calculateBoundingBox, flattenedEmojiTable, simpleHash } from "../Util"; +import { calculateBoundingBox, simpleHash } from "../Util"; import { ConstructionExecution } from "./ConstructionExecution"; import { EmojiExecution } from "./EmojiExecution"; import { structureSpawnTileValue } from "./nation/structureSpawnTileValue"; @@ -25,7 +25,7 @@ import { NukeExecution } from "./NukeExecution"; import { SpawnExecution } from "./SpawnExecution"; import { TransportShipExecution } from "./TransportShipExecution"; import { closestTwoTiles } from "./Util"; -import { BotBehavior } from "./utils/BotBehavior"; +import { BotBehavior, EMOJI_HECKLE } from "./utils/BotBehavior"; export class FakeHumanExecution implements Execution { private active = true; @@ -40,10 +40,9 @@ export class FakeHumanExecution implements Execution { private reserveRatio: number; private expandRatio: number; - private lastEmojiSent = new Map(); - private lastNukeSent: [Tick, TileRef][] = []; - private embargoMalusApplied = new Set(); - private heckleEmoji: number[]; + private readonly lastEmojiSent = new Map(); + private readonly lastNukeSent: [Tick, TileRef][] = []; + private readonly embargoMalusApplied = new Set(); constructor( gameID: GameID, @@ -57,7 +56,6 @@ export class FakeHumanExecution implements Execution { this.triggerRatio = this.random.nextInt(60, 90) / 100; this.reserveRatio = this.random.nextInt(30, 60) / 100; this.expandRatio = this.random.nextInt(15, 25) / 100; - this.heckleEmoji = ["🤡", "😡"].map((e) => flattenedEmojiTable.indexOf(e)); } init(mg: Game) { @@ -309,7 +307,7 @@ export class FakeHumanExecution implements Execution { new EmojiExecution( this.player, enemy.id(), - this.random.randElement(this.heckleEmoji), + this.random.randElement(EMOJI_HECKLE), ), ); } diff --git a/src/core/execution/utils/BotBehavior.ts b/src/core/execution/utils/BotBehavior.ts index 91c7e03a9..0774ee102 100644 --- a/src/core/execution/utils/BotBehavior.ts +++ b/src/core/execution/utils/BotBehavior.ts @@ -13,12 +13,34 @@ import { AllianceExtensionExecution } from "../alliance/AllianceExtensionExecuti import { AttackExecution } from "../AttackExecution"; import { EmojiExecution } from "../EmojiExecution"; +const emojiId = (e: typeof flattenedEmojiTable[number]) => flattenedEmojiTable.indexOf(e); +const EMOJI_ASSIST_ACCEPT = ([ + "👍", + "⛵", + "🤝", + "🎯", +] as const).map(emojiId); +const EMOJI_RELATION_TOO_LOW = ([ + "🥱", + "🤦‍♂️", +] as const).map(emojiId); +const EMOJI_TARGET_ME = ([ + "🥺", + "💀", +] as const).map(emojiId); +const EMOJI_TARGET_ALLY = ([ + "🕊️", + "👎", +] as const).map(emojiId); +export const EMOJI_HECKLE = ([ + "🤡", + "😡", +] as const).map(emojiId); + export class BotBehavior { private enemy: Player | null = null; private enemyUpdated: Tick; - private assistAcceptEmoji = flattenedEmojiTable.indexOf("👍"); - constructor( private random: PseudoRandom, private game: Game, @@ -110,26 +132,26 @@ export class BotBehavior { } assistAllies() { - outer: for (const ally of this.player.allies()) { + for (const ally of this.player.allies()) { if (ally.targets().length === 0) continue; if (this.player.relation(ally) < Relation.Friendly) { - // this.emoji(ally, "🤦"); + this.emoji(ally, this.random.randElement(EMOJI_RELATION_TOO_LOW)); continue; } for (const target of ally.targets()) { if (target === this.player) { - // this.emoji(ally, "💀"); + this.emoji(ally, this.random.randElement(EMOJI_TARGET_ME)); continue; } if (this.player.isAlliedWith(target)) { - // this.emoji(ally, "👎"); + this.emoji(ally, this.random.randElement(EMOJI_TARGET_ALLY)); continue; } // All checks passed, assist them this.player.updateRelation(ally, -20); this.setNewEnemy(target); - this.emoji(ally, this.assistAcceptEmoji); - break outer; + this.emoji(ally, this.random.randElement(EMOJI_ASSIST_ACCEPT)); + return; } } }