diff --git a/src/client/graphics/layers/EventsDisplay.ts b/src/client/graphics/layers/EventsDisplay.ts index d1d705502..34eb7ee02 100644 --- a/src/client/graphics/layers/EventsDisplay.ts +++ b/src/client/graphics/layers/EventsDisplay.ts @@ -21,6 +21,7 @@ import { EmojiUpdate, GameUpdateType, TargetPlayerUpdate, + UnitIncomingUpdate, } from "../../../core/game/GameUpdates"; import { ClientID } from "../../../core/Schemas"; import { @@ -53,6 +54,7 @@ interface Event { priority?: number; duration?: Tick; focusID?: number; + unitView?: UnitView; } @customElement("events-display") @@ -89,6 +91,7 @@ export class EventsDisplay extends LitElement implements Layer { [GameUpdateType.BrokeAlliance, (u) => this.onBrokeAllianceEvent(u)], [GameUpdateType.TargetPlayer, (u) => this.onTargetPlayerEvent(u)], [GameUpdateType.Emoji, (u) => this.onEmojiMessageEvent(u)], + [GameUpdateType.UnitIncoming, (u) => this.onUnitIncomingEvent(u)], ]); constructor() { @@ -421,6 +424,28 @@ export class EventsDisplay extends LitElement implements Layer { } } + onUnitIncomingEvent(event: UnitIncomingUpdate) { + const myPlayer = this.game.playerByClientID(this.clientID); + + if ( + event.playerID != null && + (!myPlayer || myPlayer.smallID() !== event.playerID) + ) { + return; + } + + const unitView = this.game.unit(event.unitID); + + this.addEvent({ + description: event.message, + type: event.messageType, + unsafeDescription: false, + highlight: true, + createdAt: this.game.ticks(), + unitView: unitView, + }); + } + private getMessageTypeClasses(type: MessageType): string { switch (type) { case MessageType.SUCCESS: @@ -645,7 +670,15 @@ export class EventsDisplay extends LitElement implements Layer { > ${this.getEventDescription(event)} ` - : this.getEventDescription(event)} + : event.unitView + ? html`` + : this.getEventDescription(event)} ${event.buttons ? html`
diff --git a/src/core/execution/MIRVExecution.ts b/src/core/execution/MIRVExecution.ts index 61b38df81..3a960d86a 100644 --- a/src/core/execution/MIRVExecution.ts +++ b/src/core/execution/MIRVExecution.ts @@ -81,7 +81,8 @@ export class MirvExecution implements Execution { this.separateDst = this.mg.ref(x, y); this.pathFinder.computeControlPoints(spawn, this.separateDst); - this.mg.displayMessage( + this.mg.displayIncomingUnit( + this.nuke.id(), `⚠️⚠️⚠️ ${this.player.name()} - MIRV INBOUND ⚠️⚠️⚠️`, MessageType.ERROR, this.targetPlayer.id(), diff --git a/src/core/execution/NukeExecution.ts b/src/core/execution/NukeExecution.ts index 4572eefc5..e0333f626 100644 --- a/src/core/execution/NukeExecution.ts +++ b/src/core/execution/NukeExecution.ts @@ -106,14 +106,16 @@ export class NukeExecution implements Execution { if (this.mg.hasOwner(this.dst)) { const target = this.mg.owner(this.dst) as Player; if (this.type == UnitType.AtomBomb) { - this.mg.displayMessage( + this.mg.displayIncomingUnit( + this.nuke.id(), `${this.player.name()} - atom bomb inbound`, MessageType.ERROR, target.id(), ); } if (this.type == UnitType.HydrogenBomb) { - this.mg.displayMessage( + this.mg.displayIncomingUnit( + this.nuke.id(), `${this.player.name()} - hydrogen bomb inbound`, MessageType.ERROR, target.id(), @@ -129,7 +131,7 @@ export class NukeExecution implements Execution { ); } - // after sending an nuke set the missilesilo on cooldown + // after sending a nuke set the missilesilo on cooldown const silo = this.player .units(UnitType.MissileSilo) .find((silo) => silo.tile() === spawn); diff --git a/src/core/execution/TransportShipExecution.ts b/src/core/execution/TransportShipExecution.ts index 0194c895d..9b8dfc27d 100644 --- a/src/core/execution/TransportShipExecution.ts +++ b/src/core/execution/TransportShipExecution.ts @@ -67,15 +67,6 @@ export class TransportShipExecution implements Execution { this.attacker = mg.player(this.attackerID); - // Notify the target player about the incoming naval invasion - if (this.targetID && this.targetID !== mg.terraNullius().id()) { - mg.displayMessage( - `Naval invasion incoming from ${this.attacker.displayName()}`, - MessageType.WARN, - this.targetID, - ); - } - if ( this.attacker.units(UnitType.TransportShip).length >= mg.config().boatMaxNumber() @@ -142,6 +133,16 @@ export class TransportShipExecution implements Execution { this.boat = this.attacker.buildUnit(UnitType.TransportShip, this.src, { troops: this.troops, }); + + // Notify the target player about the incoming naval invasion + if (this.targetID && this.targetID !== mg.terraNullius().id()) { + mg.displayIncomingUnit( + this.boat.id(), + `Naval invasion incoming from ${this.attacker.displayName()}`, + MessageType.WARN, + this.targetID, + ); + } } tick(ticks: number) { diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index 8eec8c263..bb57ca831 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -544,6 +544,12 @@ export interface Game extends GameMap { type: MessageType, playerID: PlayerID | null, ): void; + displayIncomingUnit( + unitID: number, + message: string, + type: MessageType, + playerID: PlayerID, + ): void; displayChat( message: string, diff --git a/src/core/game/GameImpl.ts b/src/core/game/GameImpl.ts index 698689537..1b88abad0 100644 --- a/src/core/game/GameImpl.ts +++ b/src/core/game/GameImpl.ts @@ -628,6 +628,24 @@ export class GameImpl implements Game { recipient: recipient, }); } + + displayIncomingUnit( + unitID: number, + message: string, + type: MessageType, + playerID: PlayerID, + ): void { + const id = this.player(playerID).smallID(); + + this.addUpdate({ + type: GameUpdateType.UnitIncoming, + unitID: unitID, + message: message, + messageType: type, + playerID: id, + }); + } + addUnit(u: Unit) { this.unitGrid.addUnit(u); } diff --git a/src/core/game/GameUpdates.ts b/src/core/game/GameUpdates.ts index dc9b3e313..f9b3087d9 100644 --- a/src/core/game/GameUpdates.ts +++ b/src/core/game/GameUpdates.ts @@ -38,6 +38,7 @@ export enum GameUpdateType { Emoji, Win, Hash, + UnitIncoming, } export type GameUpdate = @@ -53,7 +54,8 @@ export type GameUpdate = | TargetPlayerUpdate | EmojiUpdate | WinUpdate - | HashUpdate; + | HashUpdate + | UnitIncomingUpdate; export interface TileUpdateWrapper { type: GameUpdateType.Tile; @@ -182,3 +184,11 @@ export interface HashUpdate { tick: Tick; hash: number; } + +export interface UnitIncomingUpdate { + type: GameUpdateType.UnitIncoming; + unitID: number; + message: string; + messageType: MessageType; + playerID: number; +}