- ${playercounts.get(player)}
+ }
+};
+const ScoreBoardComponent = {
+ data() {
+ return {
+ trumpsuit: 'N/A',
+ playerScores: [],
+ };
+ },
+ template: `
+
+
Tricks Won
+
+
+
+
+
+
+
+ {{ player.name }}
+
+
+
+ {{ player.tricks }}
+
+
+
+
+ `,
+
+ methods: {
+ calculateNewScores(players, tricklist) {
+ const playercounts = new Map();
+ players.forEach(player => {
+ playercounts.set(player, 0)
+ });
+
+ tricklist.forEach(playerWonTrick => {
+ if (playerWonTrick !== "Trick in Progress" && playercounts.has(playerWonTrick)) {
+ playercounts.set(playerWonTrick, playercounts.get(playerWonTrick) + 1);
+ }
+ });
+
+ const newScores = players.map(name => ({
+ name: name,
+ tricks: playercounts.get(name) || 0,
+ }));
+
+ newScores.sort((a, b) => b.tricks - a.tricks);
+
+ return newScores;
+ },
+
+ updateNewRoundData(eventData) {
+ console.log("Vue Scoreboard Data Update Triggered: New Round!");
+
+ this.playerScores = eventData.players.map(player => ({
+ name: player,
+ tricks: 0,
+ }));
+ },
+
+ updateTrickEndData(eventData) {
+ const { playerwon, playersin, tricklist } = eventData;
+
+ console.log(`Vue Scoreboard Data Update Triggered: ${playerwon} won the trick!`);
+
+ this.playerScores = this.calculateNewScores(playersin, tricklist);
+
+
+ }
+ }
+};
+const GameInfoComponent = {
+ data() {
+ return {
+ trumpsuit: 'No Trumpsuit',
+ firstCardImagePath: '/assets/images/cards/1B.png',
+ };
+ },
+
+ template: `
+
+
Trumpsuit
+
{{ trumpsuit }}
+
+
+
First Card
+
+
+
![First Card]()
+
+
+ `,
+
+ methods: {
+ resetFirstCard(eventData) {
+ console.log("GameInfoComponent: Resetting First Card to placeholder.");
+ this.firstCardImagePath = '/assets/images/cards/1B.png';
+ },
+ updateFirstCard(eventData) {
+ const firstCardId = eventData.firstCard;
+ console.log("GameInfoComponent: Updating First Card to:", firstCardId);
+
+ let imageSource;
+ if (firstCardId === "BLANK" || !firstCardId) {
+ imageSource = "/assets/images/cards/1B.png";
+ } else {
+ imageSource = `/assets/images/cards/${firstCardId}.png`;
+ }
+ this.firstCardImagePath = imageSource;
+ },
+ updateTrumpsuit(eventData) {
+ this.trumpsuit = eventData.trumpsuit;
+ }
+ }
+};
+const TrickDisplayComponent = {
+ data() {
+ return {
+ playedCards: [],
+ };
+ },
+
+ template: `
+
+
+
+
+
![]()
+
+
+ {{ play.player }}
+
+
+
+
+ `,
+
+ methods: {
+ getCardImagePath(cardId) {
+ return `/assets/images/cards/${cardId}.png`;
+ },
+
+ clearPlayedCards() {
+ console.log("TrickDisplayComponent: Clearing played cards.");
+ this.playedCards = [];
+ },
+
+ updatePlayedCards(eventData) {
+ console.log("TrickDisplayComponent: Updating played cards.");
+
+ this.playedCards = eventData.playedCards;
+ }
+ }
+};
+function formatPlayerName(player) {
+ let name = player.name;
+ if (player.dog) {
+ name += " 🐶";
+ }
+ return name;
+}
+
+const TurnComponent = {
+ data() {
+ return {
+ currentPlayerName: 'Waiting...',
+ nextPlayers: [],
+ };
+ },
+
+ template: `
+
+
Current Player
+
{{ currentPlayerName }}
+
+
+
+ `,
+ methods: {
+ updateTurnData(eventData) {
+ console.log("TurnComponent: Updating turn data.");
+ const { currentPlayer, nextPlayers } = eventData;
+
+ this.currentPlayerName = formatPlayerName(currentPlayer);
+
+ this.nextPlayers = nextPlayers.map(player => formatPlayerName(player));
+ }
+ }
+};
+const LobbyComponent = {
+ data() {
+ return {
+ lobbyName: 'Loading...',
+ lobbyId: 'default',
+ isHost: false,
+ maxPlayers: 0,
+ players: [],
+ showKickedModal: false,
+ kickedEventData: null,
+ showSessionClosedModal: false,
+ sessionClosedEventData: null,
+ };
+ },
+
+ template: `
+
+
+
+
+
+
+
+
+
You've been kicked from the lobby.
+
You'll get redirected to the mainmenu in 5 seconds...
+
+
+
+
+
+
+
+
+
+
+
+
The session was closed.
+
You'll get redirected to the mainmenu in 5 seconds...
+
+
+
+
+
+
+
+
+
+
+
+ Lobby-Name: {{ lobbyName }}
+
+
Exit
+
+
+
+
+
+
+
+ Players: {{ players.length }} / {{ maxPlayers }}
+
+
+
+
+
+
+
+
+
+
+

+
+
+ {{ player.name }} (You)
+
+
+
+ Remove
+
+
+ Remove
+
- `
- });
- alertMessage(`${winner} won the trick!`)
- tricktable.html(newHtml);
+
+
+
+
+
+
+
+
+
+
+

+
+
+ {{ player.name }} (You)
+
+
+
+
+
+
+
+
Waiting for the host to start the game...
+
+ Loading...
+
+
+
+
+
+
+
+ `,
+
+ methods: {
+ updateLobbyData(eventData) {
+ console.log("LobbyComponent: Received Lobby Update Event.");
+
+ this.isHost = eventData.host;
+ this.maxPlayers = eventData.maxPlayers;
+ this.players = eventData.players;
+ },
+
+ setInitialData(name, id) {
+ this.lobbyName = name;
+ this.lobbyId = id;
+ },
+ startGame() {
+ globalThis.startGame()
+ },
+ leaveGame(gameId) {
+ //TODO: Needs implementation
+ },
+ handleKickPlayer(playerId) {
+ globalThis.handleKickPlayer(playerId)
+ },
+ showKickModal(eventData) {
+ this.showKickedModal = true;
+ setTimeout(() => {
+ this.kickedEventData = eventData;
+ this.showKickedModal = false;
+
+ if (typeof globalThis.receiveGameStateChange === 'function') {
+ globalThis.receiveGameStateChange(this.kickedEventData);
+ } else {
+ console.error("FATAL: receiveGameStateChange ist nicht global definiert.");
+ }
+ }, 5000);
+ },
+ showSessionClosedModal(eventData) {
+ this.sessionClosedEventData = eventData;
+ this.showSessionClosedModal = true;
+
+ setTimeout(() => {
+ this.showSessionClosedModal = false;
+
+ if (typeof globalThis.receiveGameStateChange === 'function') {
+ globalThis.receiveGameStateChange(this.sessionClosedEventData);
+ } else {
+ console.error("FATAL: receiveGameStateChange ist nicht global definiert.");
+ }
+ }, 5000);
+ }
+ }
+};
-}
-function newTrickEvent() {
- const firstCardContainer = $('#first-card-container');
- const emptyHtml = '';
- let newHtml = '';
- newHtml += `
-

- `;
- firstCardContainer.html(newHtml);
- const playedCardsContainer = $('#trick-cards-container')
- playedCardsContainer.html(emptyHtml)
-}
function requestCardEvent(eventData) {
- const player = eventData.player;
- const handElement = $('#card-slide')
- handElement.removeClass('inactive');
- canPlayCard = true;
+ //TODO: Needs correct implementation of setting the inactive class in the PlayerHandComponent
}
-
-
function receiveGameStateChange(eventData) {
const content = eventData.content;
const title = eventData.title || 'Knockout Whist';
@@ -172,162 +504,150 @@ function receiveGameStateChange(eventData) {
exchangeBody(content, title, url);
}
-function receiveCardPlayedEvent(eventData) {
- const firstCard = eventData.firstCard;
- const playedCards = eventData.playedCards;
-
- const trickCardsContainer = $('#trick-cards-container');
- const firstCardContainer = $('#first-card-container')
-
- let trickHTML = '';
- playedCards.forEach(cardCombo => {
- trickHTML += `
-
-
-
-

-
-
- ${cardCombo.player}
-
-
-
- `;
- });
- trickCardsContainer.html(trickHTML);
-
- let altText;
- let imageSrc;
- if (firstCard === "BLANK") {
- imageSrc = "/assets/images/cards/1B.png";
- altText = "Blank Card";
- } else {
- imageSrc = `/assets/images/cards/${firstCard}.png`;
- altText = `Card ${firstCard}`;
- }
-
- const newFirstCardHTML = `
-

- `;
- firstCardContainer.html(newFirstCardHTML);
-}
-function receiveLobbyUpdateEvent(eventData) {
- const host = eventData.host;
- const maxPlayers = eventData.maxPlayers;
- const players = eventData.players;
-
- const lobbyPlayersContainer = $('#players');
- const playerAmountBox = $('#playerAmount');
-
- let newHtml = ''
-
- if (host) {
- players.forEach(user => {
-
- const inner = user.self ? `
${user.name} (You)
-
Remove`
- : `
${user.name}
-
Remove
`
-
- newHtml += `
-
-

-
- ${inner}
-
-
-
`
- })
- } else {
- players.forEach(user => {
-
- const inner = user.self ? `
${user.name} (You)
` : `
${user.name}
`
-
- newHtml += `
-
-

-
- ${inner}
-
-
-
`
- })
- }
-
- lobbyPlayersContainer.html(newHtml);
- playerAmountBox.text(`Players: ${players.length} / ${maxPlayers}`);
-
-}
-function receiveKickEvent(eventData) {
- $('#kickedModal').modal({
- backdrop: 'static',
- keyboard: false
- }).modal('show');
-
- setTimeout(() => {
- receiveGameStateChange(eventData)
- }, 5000);
-}
-function receiveSessionClosedEvent(eventData) {
- $('#sessionClosed').modal({
- backdrop: 'static',
- keyboard: false
- }).modal('show');
-
- setTimeout(() => {
- receiveGameStateChange(eventData)
- }, 5000);
-}
-
-
-function receiveTurnEvent(eventData) {
- const currentPlayer = eventData.currentPlayer;
- const nextPlayers = eventData.nextPlayers;
-
- const currentPlayerNameContainer = $('#current-player-name');
- const nextPlayersContainer = $('#next-players-container');
- const nextPlayerText = $('#next-players-text');
-
- let currentPlayerName = currentPlayer.name;
- if (currentPlayer.dog) {
- currentPlayerName += " 🐶";
- }
- currentPlayerNameContainer.text(currentPlayerName);
-
- if (nextPlayers.length === 0) {
- nextPlayerText.hide();
- nextPlayersContainer.html('');
- } else {
- console.log("Length"+nextPlayers.length);
- nextPlayerText.show();
- let nextPlayersHtml = '';
- nextPlayers.forEach((player) => {
- let playerName = player.name;
- if (player.dog) {
- playerName += " 🐶";
- }
- nextPlayersHtml += `
${playerName}
`;
- });
- nextPlayersContainer.html(nextPlayersHtml);
- }
-}
function receiveRoundEndEvent(eventData) {
- const player = eventData.player
- const tricks = eventData.tricks
- alertMessage(`${player} won this round with ${tricks} tricks!`)
+ //TODO: When alert is working, set an alert that shows how won the round and with how much tricks.
}
-onEvent("ReceivedHandEvent", receiveHandEvent)
-onEvent("GameStateChangeEvent", receiveGameStateChange)
-onEvent("NewRoundEvent", newRoundEvent)
-onEvent("TrickEndEvent", trickEndEvent)
-onEvent("NewTrickEvent", newTrickEvent)
-onEvent("RequestCardEvent", requestCardEvent)
-onEvent("CardPlayedEvent", receiveCardPlayedEvent)
-onEvent("LobbyUpdateEvent", receiveLobbyUpdateEvent)
-onEvent("LeftEvent", receiveGameStateChange)
-onEvent("KickEvent", receiveKickEvent)
-onEvent("SessionClosed", receiveSessionClosedEvent)
-onEvent("TurnEvent", receiveTurnEvent)
-onEvent("RoundEndEvent", receiveRoundEndEvent)
+let playerHandApp = null;
+let scoreBoardApp = null;
+let gameInfoApp = null;
+let trickDisplayApp = null;
+let turnApp = null;
+globalThis.initGameVueComponents = function() {
+ // Initializing PlayerHandComponent
+ const app = Vue.createApp(PlayerHandComponent);
-globalThis.alertMessage = alertMessage
\ No newline at end of file
+ playerHandApp = app;
+ const mountedHand = app.mount('#player-hand-container');
+
+ if (mountedHand && mountedHand.updateHand) {
+ globalThis.updatePlayerHand = mountedHand.updateHand;
+ onEvent("ReceivedHandEvent", globalThis.updatePlayerHand);
+ console.log("PLAYER HAND SYSTEM: updatePlayerHand successfully exposed.");
+ } else {
+ console.error("FATAL ERROR: PlayerHandComponent mount failed. Check if #player-hand-container exists.");
+ }
+
+ // Initializing Scoreboard
+ if (scoreBoardApp) return
+
+ const app2 = Vue.createApp(ScoreBoardComponent)
+ scoreBoardApp = app2
+ const mountedHand2 = app2.mount('#score-table')
+ if (mountedHand2) {
+ globalThis.updateNewRoundData = mountedHand2.updateNewRoundData;
+ onEvent("NewRoundEvent", handleNewRoundEvent);
+
+ globalThis.updateTrickEndData = mountedHand2.updateTrickEndData;
+ onEvent("TrickEndEvent", globalThis.updateTrickEndData);
+ console.log("SCOREBOARD: updateNewRoundData successfully exposed.");
+ } else {
+ console.error("FATAL ERROR: Scoreboard mount failed. Check if #score-table exists.");
+ }
+ // Initializing Gameinfo
+ if (gameInfoApp) return
+
+ const app3 = Vue.createApp(GameInfoComponent)
+ gameInfoApp = app3
+ const mountedGameInfo = app3.mount('#game-info-component')
+ if(mountedGameInfo) {
+ globalThis.resetFirstCard = mountedGameInfo.resetFirstCard;
+ globalThis.updateFirstCard = mountedGameInfo.updateFirstCard;
+ globalThis.updateTrumpsuit = mountedGameInfo.updateTrumpsuit
+ onEvent("NewTrickEvent", handleNewTrickEvent);
+ console.log("GameInfo: resetFirstCard successfully exposed.");
+ } else {
+ console.error("FATAL ERROR: GameInfo mount failed. Check if #score-table exists.");
+ }
+
+ // Initializing TrickCardContainer
+ if (trickDisplayApp) return;
+ const app4 = Vue.createApp(TrickDisplayComponent);
+ trickDisplayApp = app4;
+ const mountedTrickDisplay = app4.mount('#trick-cards-container');
+
+ if (mountedTrickDisplay) {
+ globalThis.clearPlayedCards = mountedTrickDisplay.clearPlayedCards;
+ globalThis.updatePlayedCards = mountedTrickDisplay.updatePlayedCards;
+ onEvent("CardPlayedEvent", handleCardPlayedEvent)
+ console.log("TRICK DISPLAY: Handlers successfully exposed (clearPlayedCards, updatePlayedCards).");
+ } else {
+ console.error("FATAL ERROR: TrickDisplay mount failed. Check if #trick-cards-container exists.");
+ }
+
+ // Initializing TurnContainer
+ if (turnApp) return;
+ const app5 = Vue.createApp(TurnComponent)
+ turnApp = app5;
+ const mountedTurnApp = app5.mount('#turn-component')
+
+ if(mountedTurnApp) {
+ globalThis.updateTurnData = mountedTurnApp.updateTurnData;
+ onEvent("TurnEvent", globalThis.updateTurnData);
+ console.log("TURN DISPLAY: Handlers successfully exposed (clearPlayedCards, updatePlayedCards).");
+ } else {
+ console.error("FATAL ERROR: TURNAPP mount failed. Check if #trick-cards-container exists.");
+ }
+}
+let lobbyApp = null;
+globalThis.initLobbyVueComponents = function(initialLobbyName, initialLobbyId, initialIsHost, initialMaxPlayers, initialPlayers) {
+
+ if (lobbyApp) return;
+
+ const appLobby = Vue.createApp(LobbyComponent);
+ lobbyApp = appLobby;
+ const mountedLobby = appLobby.mount('#lobby-app-mount');
+
+ if (mountedLobby) {
+ mountedLobby.setInitialData(initialLobbyName, initialLobbyId);
+
+ //Damit beim erstmaligen Betreten der Lobby die Spieler etc. angezeigt werden.
+ mountedLobby.updateLobbyData({
+ host: initialIsHost,
+ maxPlayers: initialMaxPlayers,
+ players: initialPlayers
+ });
+
+ globalThis.updateLobbyData = mountedLobby.updateLobbyData;
+ globalThis.showKickModal = mountedLobby.showKickModal;
+ globalThis.showSessionClosedModal = mountedLobby.showSessionClosedModal;
+ onEvent("LobbyUpdateEvent", globalThis.updateLobbyData);
+ onEvent("KickEvent", globalThis.showKickModal);
+ onEvent("SessionClosed", globalThis.showSessionClosedModal);
+ console.log("LobbyComponent successfully mounted and registered events.");
+ } else {
+ console.error("FATAL ERROR: LobbyComponent mount failed.");
+ }
+}
+function handleCardPlayedEvent(eventData) {
+ console.log("CardPlayedEvent received. Updating Game Info and Trick Display.");
+
+ if (typeof globalThis.updateFirstCard === 'function') {
+ globalThis.updateFirstCard(eventData);
+ }
+
+ if (typeof globalThis.updatePlayedCards === 'function') {
+ globalThis.updatePlayedCards(eventData);
+ }
+}
+function handleNewTrickEvent(eventData) {
+ if (typeof globalThis.resetFirstCard === 'function') {
+ globalThis.resetFirstCard(eventData);
+ }
+
+ if (typeof globalThis.clearPlayedCards === 'function') {
+ globalThis.clearPlayedCards();
+ }
+}
+function handleNewRoundEvent(eventData) {
+ if (typeof globalThis.updateNewRoundData === 'function') {
+ globalThis.updateNewRoundData(eventData);
+ }
+ if (typeof globalThis.updateTrumpsuit === 'function') {
+ globalThis.updateTrumpsuit(eventData);
+ }
+}
+
+onEvent("GameStateChangeEvent", receiveGameStateChange)
+onEvent("LeftEvent", receiveGameStateChange)
+onEvent("RequestCardEvent", requestCardEvent)
+onEvent("RoundEndEvent", receiveRoundEndEvent)
\ No newline at end of file
diff --git a/knockoutwhistweb/public/javascripts/interact.js b/knockoutwhistweb/public/javascripts/interact.js
index 59cdc4c..c4bba34 100644
--- a/knockoutwhistweb/public/javascripts/interact.js
+++ b/knockoutwhistweb/public/javascripts/interact.js
@@ -1,59 +1,5 @@
-function handlePlayCard(card, dog) {
-
- if(!canPlayCard) return
- canPlayCard = false;
-
- const cardId = card.dataset.cardId;
-
- console.debug(`Playing card ${cardId} from hand`)
-
- const wiggleKeyframes = [
- { transform: 'translateX(0)' },
- { transform: 'translateX(-5px)' },
- { transform: 'translateX(5px)' },
- { transform: 'translateX(-5px)' },
- { transform: 'translateX(0)' }
- ];
-
- const wiggleTiming = {
- duration: 400,
- iterations: 1,
- easing: 'ease-in-out',
- fill: 'forwards'
- };
-
-
- const cardslide = $('#card-slide')
-
- const payload = {
- cardindex: cardId,
- isDog: dog
- }
- sendEventAndWait("PlayCard", payload).then(
- () => {
- card.parentElement.remove();
- cardslide.find('.handcard').each(function(newIndex) {
-
- const $innerButton = $(this).find('.btn');
- $innerButton.attr('data-card-id', newIndex);
-
- const isInDogLife = $innerButton.attr('onclick').includes("'true'") ? 'true' : 'false';
- $innerButton.attr('onclick', `handlePlayCard(this, '${isInDogLife}')`);
-
- console.debug(`Re-indexed card: Old index was ${$innerButton.attr('data-card-id')}, New index is ${newIndex}`);
- });
-
- cardslide.addClass("inactive")
- }
- ).catch(
- (err) => {
- canPlayCard = true;
- const cardslide = $('#card-slide')
- cardslide.removeClass("inactive")
- card.parentElement.animate(wiggleKeyframes, wiggleTiming);
- alertMessage(err.message)
- }
- )
+function handlePlayCard(cardidx) {
+ //TODO: Needs implementation
}
function handleSkipDogLife(button) {
@@ -79,4 +25,9 @@ function handleKickPlayer(playerId) {
}
function handleReturnToLobby() {
sendEvent("ReturnToLobby")
-}
\ No newline at end of file
+}
+
+globalThis.startGame = startGame
+globalThis.handleTrumpSelection = handleTrumpSelection
+globalThis.handleKickPlayer = handleKickPlayer
+globalThis.handleReturnToLobby = handleReturnToLobby
\ No newline at end of file