From a0353066c9aa53ffbb571f2fb449728f62fea545 Mon Sep 17 00:00:00 2001 From: evanpelle Date: Fri, 20 Sep 2024 13:14:46 -0700 Subject: [PATCH] create EventsDisplay file --- src/client/ClientGame.ts | 6 +- src/client/graphics/GameRenderer.ts | 4 +- src/client/graphics/layers/EventsDisplay.ts | 167 ++++++++++++++++++ src/client/graphics/layers/UILayer.ts | 25 +-- src/client/index.html | 2 +- src/client/styles.css | 67 +++++++ src/core/configuration/DevConfig.ts | 6 +- .../execution/AllianceRequestExecution.ts | 6 +- src/core/game/Game.ts | 9 +- src/core/game/GameImpl.ts | 14 +- src/core/game/PlayerImpl.ts | 4 + 11 files changed, 279 insertions(+), 31 deletions(-) create mode 100644 src/client/graphics/layers/EventsDisplay.ts diff --git a/src/client/ClientGame.ts b/src/client/ClientGame.ts index 260b49110..8a7e3ee65 100644 --- a/src/client/ClientGame.ts +++ b/src/client/ClientGame.ts @@ -10,7 +10,7 @@ import {TerrainMap} from "../core/game/TerrainMapLoader"; import {and, bfs, dist, manhattanDist} from "../core/Util"; import {TerrainLayer} from "./graphics/layers/TerrainLayer"; import {WinCheckExecution} from "../core/execution/WinCheckExecution"; -import {SendAllianceRequestEvent} from "./graphics/layers/UILayer"; +import {SendAllianceRequestUIEvent} from "./graphics/layers/UILayer"; @@ -122,7 +122,7 @@ export class ClientGame { this.eventBus.on(PlayerEvent, (e) => this.playerEvent(e)) this.eventBus.on(MouseUpEvent, (e) => this.inputEvent(e)) - this.eventBus.on(SendAllianceRequestEvent, (e) => this.onSendAllianceRequest(e)) + this.eventBus.on(SendAllianceRequestUIEvent, (e) => this.onSendAllianceRequest(e)) this.renderer.initialize() this.input.initialize() @@ -271,7 +271,7 @@ export class ClientGame { } } - private onSendAllianceRequest(event: SendAllianceRequestEvent) { + private onSendAllianceRequest(event: SendAllianceRequestUIEvent) { this.sendIntent({ type: "allianceRequest", clientID: this.id, diff --git a/src/client/graphics/GameRenderer.ts b/src/client/graphics/GameRenderer.ts index 120a47273..ec0d75c7e 100644 --- a/src/client/graphics/GameRenderer.ts +++ b/src/client/graphics/GameRenderer.ts @@ -8,6 +8,7 @@ import {UILayer} from "./layers/UILayer"; import {EventBus} from "../../core/EventBus"; import {TransformHandler} from "./TransformHandler"; import {Layer} from "./layers/Layer"; +import {EventsDisplay} from "./layers/EventsDisplay"; export function createRenderer(game: Game, eventBus: EventBus, clientID: ClientID): GameRenderer { @@ -18,7 +19,8 @@ export function createRenderer(game: Game, eventBus: EventBus, clientID: ClientI new TerrainLayer(game), new TerritoryLayer(game, eventBus), new NameLayer(game, game.config().theme(), transformHandler, clientID), - new UILayer(eventBus, game, game.config().theme(), clientID, transformHandler) + new UILayer(eventBus, game, clientID, transformHandler), + new EventsDisplay(eventBus, game, clientID) ] return new GameRenderer(game, eventBus, canvas, transformHandler, layers) diff --git a/src/client/graphics/layers/EventsDisplay.ts b/src/client/graphics/layers/EventsDisplay.ts new file mode 100644 index 000000000..fce2c7efd --- /dev/null +++ b/src/client/graphics/layers/EventsDisplay.ts @@ -0,0 +1,167 @@ +import {nullable} from "zod"; +import {EventBus} from "../../../core/EventBus"; +import {AllianceRequestEvent, AllianceRequestReplyEvent, Game} from "../../../core/game/Game"; +import {ClientID} from "../../../core/Schemas"; +import {Layer} from "./Layer"; + +interface Event { + description: string; + buttons?: { + text: string + className: string + action: () => void + }[]; + highlight?: boolean; +} + +export class EventsDisplay implements Layer { + private container: HTMLElement; + private events: Event[]; + private tableContainer: HTMLDivElement; + + + constructor(private eventBus: EventBus, private game: Game, private clientID: ClientID) { + const element = document.getElementById("app"); + element.style.zIndex = "1000" + if (!element) throw new Error(`Container element with id app not found`); + this.container = element; + this.events = []; + this.createTableContainer() + } + + init() { + this.eventBus.on(AllianceRequestEvent, a => this.onAllianceRequestEvent(a)) + this.eventBus.on(AllianceRequestReplyEvent, a => this.onAllianceRequestReplyEvent(a)) + this.renderTable() + } + + tick() { + } + + private createTableContainer() { + this.tableContainer = document.createElement('div'); + this.tableContainer.id = 'table-container'; + this.tableContainer.style.position = 'fixed'; + this.tableContainer.style.bottom = '0px'; // Distance from bottom + this.tableContainer.style.right = '0px'; // Distance from right + this.tableContainer.style.zIndex = '1000'; + this.tableContainer.style.backgroundColor = 'rgba(255, 255, 255, 0.0)'; + this.tableContainer.style.padding = '20px'; + this.tableContainer.style.boxShadow = '0 0 10px rgba(0,0,0,0.0)'; + document.body.appendChild(this.tableContainer); + this.tableContainer.style.minWidth = '400px'; // Set minimum width + } + + shouldTransform(): boolean { + return false + } + + onAllianceRequestEvent(event: AllianceRequestEvent): void { + const myPlayer = this.game.playerByClientID(this.clientID) + if (myPlayer == null) { + return + } + + if (event.allianceRequest.recipient() != myPlayer) { + return + } + + this.addEvent({ + description: `${event.allianceRequest.requestor().name()} requests an alliance!`, + buttons: [ + { + text: "Accept", + className: "btn", + action: () => alert('accepted'), + }, + { + text: "Reject", + className: "btn btn-info", + action: () => alert('rejected'), + } + ], + highlight: true + }); + this.renderTable() + } + + onAllianceRequestReplyEvent(event: AllianceRequestReplyEvent) { + const myPlayer = this.game.playerByClientID(this.clientID) + if (myPlayer == null) { + return + } + + if (event.allianceRequest.requestor() != myPlayer) { + return + } + + this.addEvent({ + description: `${event.allianceRequest.recipient().name()} ${event.accepted ? "accepted" : "rejected"} your alliance request`, + highlight: true + }); + this.renderTable() + } + + addEvent(event: Event): void { + this.events.push(event); + } + + removeEvent(index: number): void { + this.events.splice(index, 1); + } + + updateEvent(index: number, event: Event): void { + this.events[index] = event; + } + + render(): void { } + + renderTable(): void { + let tableHtml = ` + + + `; + + this.events.forEach((event, eventIndex) => { + tableHtml += ` + + + + `; + }); + + tableHtml += ` + +
+ ${event.description} + ${event.buttons ? '
' + event.buttons.map((btn, btnIndex) => + `` + ).join('') : ''} +
+ `; + + this.tableContainer.innerHTML = tableHtml; + + // Add event listeners to buttons + this.tableContainer.querySelectorAll('button').forEach(button => { + button.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); // Prevent the event from reaching the canvas + const target = e.target as HTMLElement; + const eventIndex = parseInt(target.getAttribute('data-event-index') || ''); + const buttonIndex = parseInt(target.getAttribute('data-button-index') || ''); + + if (!isNaN(eventIndex) && !isNaN(buttonIndex)) { + const event = this.events[eventIndex]; + const buttonAction = event.buttons?.[buttonIndex]?.action; + if (buttonAction) { + buttonAction(); + // Optionally, you might want to remove the event after the action is performed + this.removeEvent(eventIndex); + this.renderTable(); // Re-render the table if you remove the event + } + } + }); + }); + } +} \ No newline at end of file diff --git a/src/client/graphics/layers/UILayer.ts b/src/client/graphics/layers/UILayer.ts index 9fe3560a7..6646b9837 100644 --- a/src/client/graphics/layers/UILayer.ts +++ b/src/client/graphics/layers/UILayer.ts @@ -3,13 +3,11 @@ import {EventBus, GameEvent} from "../../../core/EventBus"; import {WinEvent} from "../../../core/execution/WinCheckExecution"; import {AllianceRequest, AllianceRequestReplyEvent, Game, Player} from "../../../core/game/Game"; import {ClientID} from "../../../core/Schemas"; -import {renderTroops} from "../Utils"; -import winModalHtml from '../WinModal.html'; import {RightClickEvent} from "../../InputHandler"; import {Layer} from "./Layer"; import {TransformHandler} from "../TransformHandler"; -export class SendAllianceRequestEvent implements GameEvent { +export class SendAllianceRequestUIEvent implements GameEvent { constructor( public readonly requestor: Player, public readonly recipient: Player @@ -28,7 +26,12 @@ export class UILayer implements Layer { private customMenu = document.getElementById('customMenu'); - constructor(private eventBus: EventBus, private game: Game, private theme: Theme, private clientID: ClientID, private transformHandler: TransformHandler) { + constructor( + private eventBus: EventBus, + private game: Game, + private clientID: ClientID, + private transformHandler: TransformHandler + ) { } @@ -63,7 +66,6 @@ export class UILayer implements Layer { this.initRightClickMenu() this.eventBus.on(WinEvent, (e) => this.onWinEvent(e)) this.eventBus.on(RightClickEvent, (e) => this.onRightClick(e)) - this.eventBus.on(AllianceRequestReplyEvent, (e) => this.onAllianceRequestReplyEvent(e)) } initRightClickMenu() { @@ -193,17 +195,6 @@ export class UILayer implements Layer { this.showWinModal(event.winner) } - onAllianceRequestReplyEvent(event: AllianceRequestReplyEvent) { - if (event.allianceRequest.requestor().clientID() == this.clientID) { - const recipient = event.allianceRequest.recipient().name() - if (event.accepted) { - alert(`${recipient} accepted your alliance request`) - } else { - alert(`${recipient} rejected your alliance request`) - } - } - } - showWinModal(winner: Player) { if (this.winModal) { const message = this.winModal.querySelector('#winMessage'); @@ -265,7 +256,7 @@ export class UILayer implements Layer { label: "Request Alliance", action: (): void => { this.eventBus.emit( - new SendAllianceRequestEvent(myPlayer, owner) + new SendAllianceRequestUIEvent(myPlayer, owner) ) }, } diff --git a/src/client/index.html b/src/client/index.html index fc8c8a8a9..56923d14a 100644 --- a/src/client/index.html +++ b/src/client/index.html @@ -46,7 +46,7 @@ - +