diff --git a/cardGen.js b/cardGen.js index da51b14..cd385cb 100644 --- a/cardGen.js +++ b/cardGen.js @@ -578,6 +578,10 @@ function requestDeck(itemData = null){ //itemData.component.deck[deckItem].handSize = 0; itemData.component.cardCount.hand[forPlayer] = 0; itemData.component.cardCount.board[forPlayer] = 0; + itemData.component.cardCount.shield[forPlayer] = 0; + itemData.component.cardCount.mana[forPlayer] = 0; + itemData.component.cardCount.grave[forPlayer] = 0; + itemData.component.cardCount.void[forPlayer] = 0; itemCount++; // Increment item to not overwrite } diff --git a/components.js b/components.js index 2d6dead..db55f8b 100644 --- a/components.js +++ b/components.js @@ -16,6 +16,10 @@ const component = { deck : {}, hand : {}, board : {}, + shield : {}, + mana : {}, // For some of these, the length of object/array would be better... + grave : {}, + void : {}, }, // Card Stuff diff --git a/gameMod.js b/gameMod.js index 5afeea6..ed538fe 100644 --- a/gameMod.js +++ b/gameMod.js @@ -10,6 +10,40 @@ const gameHelper = require('./gameHelper'); // actual Id would be better, but the player should be passed correctly // from the client. They can edit data, but server-side validation SHOULD prevent // in the future +function gameStart(roomId){ + + // Each player shuffles + for(const player of roomData[roomId].playerData){ + + // TODO: Make sure this only does for players, not spectators (in fut.) + shuffleDeck(roomId, player.playerDataId); + + } + + // Each player plays X shield + for(const player of roomData[roomId].playerData){ + + // TODO: Make sure this only does for players, not spectators (in fut.) + // If shieldCount is less than the 'most' shield at start of game + for(let shieldCount = 0; shieldCount < 4; shieldCount++){ + playShield(roomId, player.playerDataId); + } + + } + + // Each player draws X cards to hand + for(const player of roomData[roomId].playerData){ + + // TODO: Make sure this only does for players, not spectators (in fut.) + // + for(let handCount = 0; handCount < 1; handCount++){ + drawACard(roomId, player.playerDataId); + } + + } + +} + function passTurn(roomId, playerId){ // TODO:Check playerId and roomId before doing the stuff, to verify the user @@ -45,6 +79,49 @@ function passTurn(roomId, playerId){ } +function playShield(roomId, playerId){ + + if(global.roomData[roomId].itemData.component.shield[playerId] >= 2){ + global.socketAlert(roomData[roomId].playerData[playerId].socketId, 'Shield full; cannot play shield', 'alert'); + return false; + } + + // Change position to last position available in shield zone + let fromPosition = global.roomData[roomId].itemData.component.cardCount.deck[playerId]; // 'top' of deck + let toPosition = global.roomData[roomId].itemData.component.cardCount.shield[playerId]+1; // newest shield pos. + + // TODO: This is essential the same as in drawACard() so should be normalised into a function + // Get each card from the deck + for (const [key, value] of Object.entries(global.roomData[roomId].itemData.component.inDeck)) { + // Key is the entity here + + // If the card inDeck does not belongs to the player, skip over it + if(global.roomData[roomId].itemData.component.player[key] != playerId){ + continue; + } + + // If the card isn't the last (bottom) card of deck, skip over it + // TODO: -1 is jank, sort so listPositions all start from 1..x + if(global.roomData[roomId].itemData.component.listPosition[key] != fromPosition){ + continue; + } + + // The main man + // Move positions in hand/deck, and put the item from the deck into the shield + gameHelper.setCardPosition(roomId, playerId, key, toPosition, global.roomData[roomId].itemData.component.shield, fromPosition, global.roomData[roomId].itemData.component.inDeck); + + } + + // Reduce deckSize by 1 for the player that drew + global.roomData[roomId].itemData.component.cardCount.deck[playerId]--; + // And increase the shield size by 1 + global.roomData[roomId].itemData.component.cardCount.shield[playerId]++; + + // Then emit the deckSize and hand size to all the player's sockets + global.socketResponsePlayedShield(roomId, playerId); + +} + function drawACard(roomId, playerId){ if(global.roomData[roomId].itemData.component.cardCount.hand[playerId] >= 2){ @@ -103,8 +180,11 @@ function drawACard(roomId, playerId){ } +function playManaFromHand(roomId, playerId, position){ + playFromHand(roomId, playerId, position, true); +} // TODO: Rename and rejig the 3 play from hand functions -function playFromHand(roomId, playerId, position){ +function playFromHand(roomId, playerId, position, mana = false){ let cardId = null; // Get the cardId of the card from position within players hand @@ -129,21 +209,28 @@ function playFromHand(roomId, playerId, position){ } // Attempt to play the card from hand - if(!playACardFromHand(roomId, playerId, cardId)){ + if(!playACardFromHand(roomId, playerId, cardId, mana)){ return false; } } -function playACardFromHand(roomId, playerId, cardId){ +function playACardFromHand(roomId, playerId, cardId, mana = false){ // Add the card to field (and its effect to 'stack') or spell to the 'stack' - if(playACard(roomId, playerId, cardId, 'hand') !== true){ + if(playACard(roomId, playerId, cardId, 'hand', mana) !== true){ // TODO: Return socket to player about 'illegal move' and why return false; } + if(mana){ + global.socketResponsePlayManaFromHand(roomId, playerId, cardId); + return true; + } + + // TODO: Maybe update with 'location played to' so animations, draws, etc. are correct global.socketResponsePlayFromHand(roomId, playerId, cardId); + // TODO: Above can probably be the same/similar to what is added to the roomData on // client-end (when it's fully done) @@ -154,8 +241,14 @@ function playACardFromHand(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){ +function playACard(roomId, playerId, cardId, playedFrom, mana = false){ + // Play a mana (a card that was played as mana, loses it's normal card data) + if(mana){ + // Play to board. If there's a 'onPlay' effect, add that to the 'stack' + return playMana(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' @@ -256,6 +349,40 @@ function playAToken(roomId, playerId, cardId, playedFrom){ return false; return true; } +function playMana(roomId, playerId, cardId, playedFrom){ + + console.log('playMana'); + + // TODO: Check if mana can be played (default 10 max) + + // TODO: Check if a mana has already been played this turn (default 1 per turn per player) + + if(playedFrom == 'hand'){ + // Remove from hand + removeFromHand(roomId, playerId, cardId); + + // Add card to mana zone + global.roomData[roomId].itemData.component.mana[cardId] = cardId; + global.roomData[roomId].itemData.component.cardCount.mana[playerId]++; + + console.log(global.roomData[roomId].itemData.component.mana); + console.log(global.roomData[roomId].itemData.component.cardCount.mana[playerId]); + + // Change list positions of hand and mana + gameHelper.setCardPosition(roomId, playerId, cardId + , global.roomData[roomId].itemData.component.cardCount.mana[playerId] + , global.roomData[roomId].itemData.component.mana + , global.roomData[roomId].itemData.component.listPosition[cardId] + , global.roomData[roomId].itemData.component.hand + ); + + // Mana has been played + return true; + } + + return false; + +} // Not 100% sure how to implement the stack // TODO: Make it better @@ -460,6 +587,8 @@ module.exports = { ,drawACard ,shuffleDeck ,playFromHand + ,playManaFromHand ,acceptResolveStack + ,gameStart }; diff --git a/public/js/canvas/draw.js b/public/js/canvas/draw.js index ddcff89..c14b0f8 100644 --- a/public/js/canvas/draw.js +++ b/public/js/canvas/draw.js @@ -7,6 +7,8 @@ function drawGameBoard(){ calculateDeckPositions(); calculateHandPositions(); calculateBoardPositions(); + calculateShieldPositions(); + calculateManaPositions(); drawEntities(); @@ -146,6 +148,122 @@ function calculateBoardPositions(){ } } +function calculateShieldPositions(){ + + for (const [key, value] of Object.entries(gameData.shield)) { + + // key is entity Id here + let cardsOnBoard = 0; + let position = 0; + + let fromX = 0; + let fromY = 0; + let split = 0; + + let shieldScale = .5; // TODO: Make global (like handScale) + + switch(gameData.player[key]){ + + // Set position for player hand (all the time at current) + case gameData.playerId: + + position = gameData.listPosition[key]; + + fromX = 60; + fromY = 300; + + // i-1 here as it's based on 0 being start, like array. + // TODO: Not sure if I want to start elements at 1 (for clienty) or 0 (for programmy) + if(position-1>=2){ split = 1; } + + gameData.position[key] = [ + (fromX+((position%2)*cardMargin)) +(position%2*(cardWidth*shieldScale)) + ,canvas.height-fromY+(split*(cardHeight*shieldScale)+(cardMargin*split)) + ]; + + gameData.size[key] = [cardWidth * shieldScale, cardHeight * shieldScale]; + + break; + + // Opponent + case gameData.opponentId: + + position = gameData.listPosition[key]; + + fromX = canvas.width-60; + fromY = 300; + + if(position-1>=2){ split = 1; } + + // i%2 0 = 0, 1 = 1, 2 = 0, 3 = 1 to prevent margin from X/Y axis, and just between cards + gameData.position[key] = [ + (fromX+((position%2)*cardMargin)) +(position%2*(cardWidth*shieldScale)-(cardWidth*2*shieldScale)) + ,fromY+(split*(cardHeight*shieldScale)+(cardMargin*split)-((cardHeight*2*shieldScale) + cardMargin)) + ]; + + gameData.size[key] = [cardWidth * shieldScale, cardHeight * shieldScale]; + + break; + + } + } + +} +function calculateManaPositions(){ + + for (const [key, value] of Object.entries(gameData.mana)) { + + // key is entity Id here + let cardsOnBoard = 0; + let position = 0; + + let fromX = 0; + let fromY = 0; + + let manaScale = .3; + + switch(gameData.player[key]){ + + // Set position for player hand (all the time at current) + case gameData.playerId: + + position = gameData.listPosition[key] - 1; // Position starts at 1 + + fromX = 60; + fromY = 60 + cardHeight*manaScale; + + gameData.position[key] = [ + (fromX)+(position*(cardWidth*manaScale)+cardMargin*position) + ,canvas.height-fromY + ]; + + gameData.size[key] = [cardWidth * manaScale, cardHeight * manaScale]; + + break; + + // Opponent + case gameData.opponentId: + + position = gameData.listPosition[key] - 1; // Position starts at 1 + + fromX = 60; + fromY = 60;// + cardHeight*manaScale; + + gameData.position[key] = [ + // TODO: correct (then again all position need correcting tbf) + canvas.width - fromX-cardWidth*manaScale-(position*(cardWidth*manaScale))-cardMargin*position + ,fromY + ]; + + gameData.size[key] = [cardWidth * manaScale, cardHeight * manaScale]; + + break; + + } + } + +} + // TODO: Move this function elsewhere, not really a draw function function calculateCardSpacing(positionInt, size, standardSize){ @@ -164,6 +282,7 @@ function drawEntities(){ // If the entity has a position AND a size, we can print it if(gameData.size[key] !== undefined){ + // Should prolly switch from ifs somehow, but it works for now // If the entity is a deck if(key in gameData.deck){ drawDeck(key); @@ -179,6 +298,16 @@ function drawEntities(){ drawCardOnBoard(key); } + // If shield + if(key in gameData.shield){ + drawShield(key); + } + + // Mana + if(key in gameData.mana){ + drawMana(key); + } + if(key in gameData.inInteractionMenu){ // Add the menu with 'play', 'activate effect', 'inspect', etc. drawInteractionMenu(key); @@ -253,6 +382,22 @@ function drawCardOnBoard(entity){ drawCardDetails(entity); +} +function drawShield(entity){ + + // TODO: Tapped + drawCardBack(entity); + +} +function drawMana(entity){ + + // TODO: Show the colour/Icon of the mana for ease when tapping, etc. + console.log('drawMana'); + console.log(entity); + + // TODO: Tapped + drawCardBack(entity); + } // The draw all the card data, name, colour, etc. diff --git a/public/js/canvas/interaction.js b/public/js/canvas/interaction.js index 208c82e..a4b0d8d 100644 --- a/public/js/canvas/interaction.js +++ b/public/js/canvas/interaction.js @@ -67,6 +67,10 @@ canvas.addEventListener('click', function(event) { requestPlayFromHand(gameData.listPosition[gameData.inInteractionMenu[Object.keys(gameData.inInteractionMenu)[0]]]) } + if(key == 'Play as Mana'){ + requestPlayManaFromHand(gameData.listPosition[gameData.inInteractionMenu[Object.keys(gameData.inInteractionMenu)[0]]]) + } + console.log(key); // After an interaction, clear the menu to prevent redraw diff --git a/public/js/game/components.js b/public/js/game/components.js index 3dd9e62..e77259c 100644 --- a/public/js/game/components.js +++ b/public/js/game/components.js @@ -16,6 +16,10 @@ let gameData = { deck : {}, hand : {}, board : {}, + shield : {}, + mana : {}, + grave : {}, + void : {}, }, inInteractionMenu : {}, @@ -29,6 +33,10 @@ let gameData = { deck : {}, hand : {}, board : {}, + shield : {}, + mana : {}, + grave : {}, + void : {}, // Local components, not done on serverside // calculated, etc. by client diff --git a/public/js/game/dataUpdate.js b/public/js/game/dataUpdate.js index 106906b..2c5ec4d 100644 --- a/public/js/game/dataUpdate.js +++ b/public/js/game/dataUpdate.js @@ -82,6 +82,21 @@ function updateBoard(data){ gameData.cardColours = data.cardColours; //console.log(data); } +function updateShield(data){ + console.log('TODO: updateShield correctly'); + console.log(data); + gameData.shield = data.shield; + gameData.listPosition = data.listPosition; + // TODO: Tapped +} +function updateMana(data){ + console.log('TODO: updateMana correctly'); + console.log(data); + gameData.mana = data.mana; + gameData.listPosition = data.listPosition; + gameData.cardData = data.cardData; + gameData.cardColours = data.cardColours; +} // To prevent typical functionality (draw, etc.) // if there's a stack in play. diff --git a/public/js/game/socket.js b/public/js/game/socket.js index 5b6a016..b855da5 100644 --- a/public/js/game/socket.js +++ b/public/js/game/socket.js @@ -73,6 +73,28 @@ socket.on('responsePlayFromHand', function (data) { console.log('<< playFromHand'); console.log(data); }); +function requestPlayManaFromHand(listPosition){ + console.log('>> playManaFromHand'); + socket.emit('playManaFromHand', gameData.roomId, gameData.playerId, listPosition); +} +socket.on('responseUpdateMana', function (data) { + // Return boardData, update hand + console.log('<< updateMana'); + console.log(data); + updateMana(data); + drawGameBoard(); +}); + +socket.on('responsePlayedShield', function (data) { + // The playerId that played it for animations + console.log('<< playedShield'); + drawGameBoard(); +}); +socket.on('responseUpdateShield', function (data) { + console.log('<< updateShield'); + console.log(data); + updateShield(data); +}); // Stack socket.on('responseAddToStack', function (data) { diff --git a/rooms.js b/rooms.js index 2c5b4a0..d2a1fc0 100644 --- a/rooms.js +++ b/rooms.js @@ -1,4 +1,5 @@ const roomMod = require('./roomMod'); +const gameMod = require('./gameMod'); // Variables for server overall let numRooms = 0; @@ -205,6 +206,7 @@ async function startGame(roomId){ // Each player then gets sent the roomGeneration stuff // TODO:They should recieve different data based on what they can see/interact + for (const clientId of clients) { const clientSocket = global.io.sockets.sockets.get(clientId); @@ -230,6 +232,8 @@ async function startGame(roomId){ } + // Start game gameMod? + gameMod.gameStart(roomId); } diff --git a/server.js b/server.js index 7efc4d8..a94f6de 100644 --- a/server.js +++ b/server.js @@ -66,6 +66,9 @@ function onConnection(socket){ socket.on('playFromHand', function(roomId, playerId, listPosition) { gameMod.playFromHand(roomId, playerId, listPosition); }); + socket.on('playManaFromHand', function(roomId, playerId, listPosition) { + gameMod.playManaFromHand(roomId, playerId, listPosition); + }); socket.on('requestResolveStack', function(roomId, playerId) { gameMod.acceptResolveStack(roomId, playerId); @@ -170,6 +173,13 @@ global.socketResponseUpdateBoard = function(roomId){ // to the player who's side it's on global.sendToEachSocket(roomId, 'responseUpdateBoard', data); +} +global.socketResponseUpdateMana = function(roomId){ + + // TODO: Only return the data that's needed, no everything + let data = global.roomData[roomId].itemData.component; + global.sendToEachSocket(roomId, 'responseUpdateMana', data); + } global.socketResponsePlayFromHand = function(roomId, playerId, cardId){ @@ -188,6 +198,35 @@ global.socketResponsePlayFromHand = function(roomId, playerId, cardId){ // So the animations can be played with the new cardData (in future) global.sendToEachSocket(roomId, 'responsePlayFromHand', cardId); } +global.socketResponsePlayManaFromHand = function(roomId, playerId, cardId){ + + console.log('>> '+roomData[roomId].playerData[playerId].playerId+' played mana from hand'); + + // Return the new cardCounts for hand/deck/grave, etc. + global.socketReturnCardCounts(roomId); + + // Update hand of player that card's hand was played from (using existing logic) + global.socketResponsePlayerHandData(roomId, playerId); + + // Update the mana (for both players) + global.socketResponseUpdateMana(roomId); + + // So the animations can be played with the new cardData (in future) + //global.sendToEachSocket(roomId, 'responsePlayFromHand', cardId); +} + +global.socketResponsePlayedShield = function(roomId, playerId){ + + //global.socketReturnCardCounts(roomId, 'responseDrawCard'); + + // Return playerId of who played a shield so it can be added then animated + global.sendToEachSocket(roomId, 'responsePlayedShield', playerId); + + // Date for shield + let data = global.roomData[roomId].itemData.component; + global.sendToEachSocket(roomId, 'responseUpdateShield', data); + +} // Stack global.socketResponseAddToStack = function(roomId){