From 7edda638d48ce86d95d4e69ddcd9307223153de8 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 17 Nov 2024 16:38:25 +0000 Subject: [PATCH] Start of 'playCard' functionality --- cardGen.js | 13 +++ components.js | 3 + gameMod.js | 160 ++++++++++++++++++++++++++++++++ public/js/canvas/interaction.js | 5 + public/js/game/socket.js | 8 ++ server.js | 68 +++++++++----- 6 files changed, 233 insertions(+), 24 deletions(-) diff --git a/cardGen.js b/cardGen.js index 5ab9fcc..51eab33 100644 --- a/cardGen.js +++ b/cardGen.js @@ -508,6 +508,19 @@ function requestDeck(itemData = null){ itemData.component.inDeck[itemCount] = true; // Not sure what to store here itemData.component.listPosition[itemCount] = itemData.component.cardCount.deck[forPlayer] + 1; + // Types in new component + switch(builtCards[deckListItem.cardId].type){ + case(1): // Unit + itemData.component.type.unit[itemCount] = itemCount; + break; + case(2): // Spell + itemData.component.type.spell[itemCount] = itemCount; + break; + case(3): // Token + itemData.component.type.token[itemCount] = itemCount; + break; + } + // Associate the card with the deck // TODO: Change deckIn to something more sensical deckIn[itemCount] = deckItem; diff --git a/components.js b/components.js index 8b59d6a..3ae34e6 100644 --- a/components.js +++ b/components.js @@ -38,6 +38,9 @@ const component = { cardSprite : {}, // id, position in spritesheet [0,4] e.g. //cardPlayer = {}, + // position 1..x, card, effect, effect part + stack : {}, + // Deck Stuff? deckIn : {}, deckData : {}, diff --git a/gameMod.js b/gameMod.js index 41691a0..1753ebc 100644 --- a/gameMod.js +++ b/gameMod.js @@ -103,6 +103,165 @@ function drawACard(roomId, playerId){ } +// TODO: Rename and rejig the 3 play from hand functions +function playFromHand(roomId, playerId, position){ + + let cardId = null; + // Get the cardId of the card from position within players hand + for (const [key, value] of Object.entries(global.roomData[roomId].itemData.component.hand)) { + // Key is the entity here + + // If the card in hand's position does not match the position passed, skip it + if(global.roomData[roomId].itemData.component.listPosition[key] != position){ + continue; + } + + cardId = key; + break; + + } + + // Then play the card + if(cardId == null){ + // TODO: Respond to player (who triggered play) that this + // is an 'illegal/errored' move via socket + return false; + } + + playACardFromHand(roomId, playerId, cardId); + +} + +function playACardFromHand(roomId, playerId, cardId){ + + // Add the card to field (and its effect to 'stack') or spell to the 'stack' + if(playACard(roomId, playerId, cardId, 'hand') !== true){ + // TODO: Return socket to player about 'illegal move' and why + return false; + } + + // If the card can be played/had been + // Reduce handSize by 1 for the player that played the card + global.roomData[roomId].itemData.component.cardCount.hand[playerId]--; + + + // TODO: Send a socket response for 'played a card from hand' with cardData + // of said card. This is sent so that it can be 'chained' and added to the stack + // On play, it is put onto field/activated but the effect(s) don't occur until both/all + // players have a chance to 'chain', once the 'chain' is completed, the effect(s) trigger + global.socketResponsePlayFromHand(roomId, playerId, cardId); + + + +} + +// 'Play' a card is activation with cost (triggering play events) +// 'Summon' puts it onto the board without play events +// yada yada to think about in future +function playACard(roomId, playerId, cardId, playedFrom){ + + // Play a unit + if(cardId in global.roomData[roomId].itemData.component.type.unit){ + // Play to board. If there's a 'onPlay' effect, add that to the 'stack' + return playAUnit(roomId, playerId, cardId, playedFrom); + } + + // Cast a spell + if(cardId in global.roomData[roomId].itemData.component.type.spell){ + // Add the card/effect onto the 'stack'. When complete/cancelled send to grave + return playASpell(roomId, playerId, cardId, playedFrom); + } + + // Add a token + if(cardId in global.roomData[roomId].itemData.component.type.token){ + // ???? Tokens maybe just onto other cards as 'equips' or as standalones? IDK + return playAToken(roomId, playerId, cardId, playedFrom); + } + +} + +function playAUnit(roomId, playerId, cardId, playedFrom){ + + console.log('playAUnit'); + + // TODO: Costs + +} +function playASpell(roomId, playerId, cardId, playedFrom){ + + console.log('playASpell'); + + // TODO: Pay costs (Need to play mana first...) + + // TODO: If spell has different effects, select which one/ensure + // correct one is used based on criteria + + // Add to stack (each part of the spells effect) + // TODO: Use actual effects, for now just adding a 'drawCard' for testing + + addToStack(roomId, playerId, cardId, null); + +} +function playAToken(roomId, playerId, cardId, playedFrom){ + +} + +// Not 100% sure how to implement the stack +// TODO: Make it better +// TODO: Make it do actual things, currently just adds 'drawCard' effect +function addToStack(roomId, playerId, cardId, effectId){ + + // Stack does its own effect, or 'counter' etc. the card prior to it on the stack + // etc. etc. + // TODO: Add card effect to stack in reverse order OR have the stack work from x..0 + // prolly the latter, makes sense to me + + let stack = global.roomData[roomId].itemData.component.stack; + let stackLength = Object.keys(stack).length; + + // TODO: First ensure the cardEffects are added in their step order 1..x + // Add as next event in the stack 1..x + // TODO: Use actual effect, not just 'draw' as that's just for testing + global.roomData[roomId].itemData.component.stack[stackLength + 1] = + { + 'cardId': cardId + ,'effect': null + ,'effectStep': null + ,'targetCard': null + ,'targetPlayer': playerId + }; + + console.log(global.roomData[roomId].itemData.component.stack); + + // TODO: TEMP, this will need to wait for a 'resolve' accept from both players before the stack + // would trigger. + resolveStack(roomId); + +} + +function resolveStack(roomId){ + + // Does the next effect in the stack, if something + // is to chain onto the stack that would instead trigger + // 'addToStack' after paying any costs + + // If there is anything in the stack + let stackLength = Object.keys(global.roomData[roomId].itemData.component.stack).length; + if(stackLength > 0){ + + // Trigger the last (most recently added to) the stack effect + // THIS WILL NOW ACTUALLY CAST THE EFFECT STEP WITHOUT INTERRUPT + // While the stack is being resolved their are no counters/chains until + // the next stack action which players will get option to chain or not again + + console.log( + global.roomData[roomId].itemData.component.stack[stackLength] + ); + + } + +} + // Shuffle the deck 'randomly' for a certain player function shuffleDeck(roomId, playerId){ @@ -191,5 +350,6 @@ module.exports = { ,getPlayerHandData ,drawACard ,shuffleDeck + ,playFromHand }; diff --git a/public/js/canvas/interaction.js b/public/js/canvas/interaction.js index ebf5026..d70b504 100644 --- a/public/js/canvas/interaction.js +++ b/public/js/canvas/interaction.js @@ -62,6 +62,11 @@ canvas.addEventListener('click', function(event) { continue; } + // TODO: Checks for the actual entities position too + if(key == 'Play to Board'){ + requestPlayFromHand(gameData.listPosition[gameData.inInteractionMenu[Object.keys(gameData.inInteractionMenu)[0]]]) + } + console.log(key); // Then return true to prevent another interaction diff --git a/public/js/game/socket.js b/public/js/game/socket.js index 057def7..3f1fac1 100644 --- a/public/js/game/socket.js +++ b/public/js/game/socket.js @@ -53,6 +53,14 @@ socket.on('responseShuffleDeck', function (data) { // not a one off draw after emits }); +function requestPlayFromHand(listPosition){ + console.log('>> playFromHand'); + socket.emit('playFromHand', gameData.roomId, gameData.playerId, listPosition); +} +socket.on('responsePlayFromHand', function (data) { + console.log('<< playFromHand'); +}); + // Functions like this would be elsewhere, do client-side // validation THEN request stuff from the server? diff --git a/server.js b/server.js index 3485d85..d543604 100644 --- a/server.js +++ b/server.js @@ -63,6 +63,10 @@ function onConnection(socket){ gameMod.shuffleDeck(roomId, playerId); }); + socket.on('playFromHand', function(roomId, playerId, listPosition) { + gameMod.playFromHand(roomId, playerId, listPosition); + }); + } global.getPlayerSocketFromRoom = function(playerId, roomId){ @@ -71,6 +75,21 @@ global.getPlayerSocketFromRoom = function(playerId, roomId){ } +global.sendToEachSocket = function(roomId, responseName, data){ + + console.log(responseName); + + let clients = global.io.sockets.adapter.rooms.get(roomId); + for (const clientId of clients) { + + const clientSocket = global.io.sockets.sockets.get(clientId); + // Send to a client socket + global.io.to(clientSocket.id).emit(responseName, data); + + } + +} + // Globals for easier clientside alerts/logs, etc. global.socketAlert = function(socket, message, type = 'alert'){ global.io.to(socket).emit( @@ -82,21 +101,12 @@ global.socketAlert = function(socket, message, type = 'alert'){ // TODO: include spectators when added global.socketResponsePassTurn = function(roomId){ - let clients = global.io.sockets.adapter.rooms.get(roomId); - for (const clientId of clients) { - - const clientSocket = global.io.sockets.sockets.get(clientId); - console.log('>> '+clientSocket.playerId+' passed turn'); + let data = { + 'playerTurn': global.roomData[roomId].itemData.component.playerTurn, + 'turn': global.roomData[roomId].itemData.component.turn, + }; - // Send the data back. Whose turn it is, and what turn - let turnData = { - 'playerTurn': global.roomData[roomId].itemData.component.playerTurn, - 'turn': global.roomData[roomId].itemData.component.turn, - }; - - global.io.to(clientSocket.id).emit('responsePassTurn', turnData); - - } + global.sendToEachSocket(roomId, 'responsePassTurn', data); } @@ -104,19 +114,17 @@ global.socketResponsePassTurn = function(roomId){ // TODO: spectators in future, won't comment about this from now on global.socketResponseDrawCard = function(roomId, playerId){ - let clients = global.io.sockets.adapter.rooms.get(roomId); - for (const clientId of clients) { + console.log('>> '+roomData[roomId].playerData[playerId].playerId+' drew card'); - const clientSocket = global.io.sockets.sockets.get(clientId); - console.log('>> '+roomData[roomId].playerData[playerId].playerId+' drew card'); + global.socketReturnCardCounts(roomId); - // Send the data back - global.io.to(clientSocket.id).emit( - 'responseDrawCard' - ,global.roomData[roomId].itemData.component.cardCount - ); +} - } +global.socketReturnCardCounts = function(roomId){ + + let data = global.roomData[roomId].itemData.component.cardCount; + + global.sendToEachSocket(roomId, 'responseDrawCard', data); } @@ -142,3 +150,15 @@ global.socketResponseShuffleDeck = function(roomId, playerId, hasShuffled){ } +global.socketResponsePlayFromHand = function(roomId, playerId, cardId){ + + console.log('>> '+roomData[roomId].playerData[playerId].playerId+' played from hand'); + + // Return the new cardCounts for hand/deck/grave, etc. + global.socketReturnCardCounts(roomId); + + // Return the card being played TODO: Return all related card data, not just the ID + global.sendToEachSocket(roomId, 'responsePlayFromHand', cardId); + +} +