diff --git a/cardGen.js b/cardGen.js
index 51eab33..da51b14 100644
--- a/cardGen.js
+++ b/cardGen.js
@@ -577,6 +577,7 @@ function requestDeck(itemData = null){
// Set the handSize to 0, will need moving somewhere else
//itemData.component.deck[deckItem].handSize = 0;
itemData.component.cardCount.hand[forPlayer] = 0;
+ itemData.component.cardCount.board[forPlayer] = 0;
itemCount++; // Increment item to not overwrite
}
diff --git a/components.js b/components.js
index 3ae34e6..2d6dead 100644
--- a/components.js
+++ b/components.js
@@ -15,6 +15,7 @@ const component = {
cardCount : {
deck : {},
hand : {},
+ board : {},
},
// Card Stuff
diff --git a/gameMod.js b/gameMod.js
index 1753ebc..5afeea6 100644
--- a/gameMod.js
+++ b/gameMod.js
@@ -128,7 +128,10 @@ function playFromHand(roomId, playerId, position){
return false;
}
- playACardFromHand(roomId, playerId, cardId);
+ // Attempt to play the card from hand
+ if(!playACardFromHand(roomId, playerId, cardId)){
+ return false;
+ }
}
@@ -140,18 +143,11 @@ function playACardFromHand(roomId, playerId, cardId){
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);
+ // TODO: Above can probably be the same/similar to what is added to the roomData on
+ // client-end (when it's fully done)
-
+ return true;
}
@@ -180,12 +176,50 @@ function playACard(roomId, playerId, cardId, playedFrom){
}
+function hasSpaceOnBoard(roomId, playerId){
+ // TODO:
+ return true;
+}
+function removeFromHand(roomId, playerId, cardId){
+ console.log('remove from hand');
+ if(cardId in global.roomData[roomId].itemData.component.hand){
+ delete(global.roomData[roomId].itemData.component.hand[cardId]);
+ }
+ global.roomData[roomId].itemData.component.cardCount.hand[playerId]--;
+}
+
function playAUnit(roomId, playerId, cardId, playedFrom){
console.log('playAUnit');
+ // TODO: Make work, AND allow to play to opponent board (in future)
+ if(hasSpaceOnBoard(roomId, playerId) !== true){
+ return false
+ }
+
// TODO: Costs
+ if(playedFrom == 'hand'){
+
+ // Remove from hand
+ removeFromHand(roomId, playerId, cardId);
+
+ // Add unit to board
+ global.roomData[roomId].itemData.component.board[cardId] = cardId;
+ global.roomData[roomId].itemData.component.cardCount.board[playerId]++;
+
+ // Change list positions of hand and board
+ // Next position on board (using cardCount to determine here)
+ // From current position in hand (the listPosition of the entity at this current point)
+ gameHelper.setCardPosition(roomId, playerId, cardId, global.roomData[roomId].itemData.component.cardCount.board[playerId], global.roomData[roomId].itemData.component.board, global.roomData[roomId].itemData.component.listPosition[cardId], global.roomData[roomId].itemData.component.hand);
+
+ // TODO: unit onPlay effects to the stack
+
+ }
+
+ // Add to board
+ return true;
+
}
function playASpell(roomId, playerId, cardId, playedFrom){
@@ -196,14 +230,31 @@ function playASpell(roomId, playerId, cardId, playedFrom){
// TODO: If spell has different effects, select which one/ensure
// correct one is used based on criteria
+ if(playedFrom == 'hand'){
+ // Remove from hand
+ console.log(cardId);
+ console.log(global.roomData[roomId].itemData.component.hand);
+
+ // Remove from ahnd
+ removeFromHand(roomId, playerId, cardId);
+ // if Spell when it's final effect finished (or removed) from stack, it should get
+ // added to grave then
+
+ }
+
+ // If card was played, add its effect(s) to the stack
+ // If it should be added to stack (spell, or onPlay effect) do so
// 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);
+ // Spell can/'has' been played
+ return true;
+
}
function playAToken(roomId, playerId, cardId, playedFrom){
-
+ return false;
+ return true;
}
// Not 100% sure how to implement the stack
@@ -233,14 +284,52 @@ function addToStack(roomId, playerId, cardId, effectId){
console.log(global.roomData[roomId].itemData.component.stack);
+ // Send addToStack response to trigger any animations, etc.
+ global.socketResponseAddToStack(roomId);
+
// TODO: TEMP, this will need to wait for a 'resolve' accept from both players before the stack
// would trigger.
+ //resolveStack(roomId);
+
+ // TODO: Improve this, potentially drop out of function, and have a while stack > 0
+ // do the stack stuff. If it's <= 0 then other functionality is as normal
+ // Need to write a game loop for this rather than a
+ // nested function calling the getStackResponse.
+ getStackResponse(roomId);
+
+}
+
+function getStackResponse(roomId){
+
+ // If there's something in the stack both/all players must accept to resolve
+ // and/or have a chance to play a counter/chain card/effect atop of the current
+ // top of the stack
+
+ // TODO: Opponent gets chance to chain first, then player
+ // if opponent chained, player gets to chain that chain first before stopping
+ // opponent double chaining
+
+ global.socketGetStackResponse(roomId);
+
+}
+
+function acceptResolveStack(roomId, playerId){
+
+ // TODO: Make so each player needs to accept
+ // with whoever is to counter getting to ability to chain first
+
+ // Once the player has resolved, the next player gets the option to chain/resolve
+
+ // If all players have resolved, then resolve the top of the stack
resolveStack(roomId);
}
function resolveStack(roomId){
+ // Resolve the stack if all players have requested
+ // to resolve the stack, and not chain anything atop of it
+
// Does the next effect in the stack, if something
// is to chain onto the stack that would instead trigger
// 'addToStack' after paying any costs
@@ -249,14 +338,25 @@ function resolveStack(roomId){
let stackLength = Object.keys(global.roomData[roomId].itemData.component.stack).length;
if(stackLength > 0){
+ // Send the 'resolve' response to room to trigger any animations, etc.
+ global.socketResponseResolveStack(roomId);
+
// 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]
- );
+
+ let stackTrigger = global.roomData[roomId].itemData.component.stack[stackLength];
+
+ // TODO: actually trigger the correct effect, etc.
+ // check if targets, check validity, etc. then trigger
+
+ // TODO: Remove drawACard and use actual triggers/effects
+ drawACard(roomId, stackTrigger.targetPlayer);
+
+ // Once the effect atop the stack has triggered, remove it from the stack
+ delete(global.roomData[roomId].itemData.component.stack[stackLength]);
}
@@ -335,6 +435,15 @@ function getPlayerHandData(roomId, playerId){
}
}
+
+
+ // TODO: This is here to prevent overwriting with less content when a draw happens.
+ // Will want reverting at some point (or other functions for returning only certain bits
+ // everywhere else should be written)
+
+ //handEntities = global.roomData[roomId].itemData.component.hand;
+ handPositions = global.roomData[roomId].itemData.component.listPosition;
+ handCardData = global.roomData[roomId].itemData.component.cardData;
return {
'handEntities': handEntities,
@@ -351,5 +460,6 @@ module.exports = {
,drawACard
,shuffleDeck
,playFromHand
+ ,acceptResolveStack
};
diff --git a/public/index.html b/public/index.html
index c637292..5caa311 100644
--- a/public/index.html
+++ b/public/index.html
@@ -21,6 +21,7 @@
+
diff --git a/public/js/canvas/draw.js b/public/js/canvas/draw.js
index 12133ff..99cffd2 100644
--- a/public/js/canvas/draw.js
+++ b/public/js/canvas/draw.js
@@ -6,6 +6,7 @@ function drawGameBoard(){
drawPlayerNames();
calculateDeckPositions();
calculateHandPositions();
+ calculateBoardPositions();
drawEntities();
@@ -100,6 +101,50 @@ function calculateHandPositions(){
}
}
+}
+// TODO: Move from draw into somewhere else
+function calculateBoardPositions(){
+
+ for (const [key, value] of Object.entries(gameData.board)) {
+
+ // key is entity Id here
+ let cardsOnBoard = 0;
+ let position = 0;
+
+ switch(gameData.player[key]){
+
+ // Set position for player hand (all the time at current)
+ case gameData.playerId:
+
+ cardsOnBoard = gameData.cardCount.board[gameData.playerId];
+ position = gameData.listPosition[key];
+
+ gameData.position[key] = [
+ canvas.width/2 - (cardWidth * (cardsOnBoard - (position+1)) - (cardMargin * (position+1)))
+ ,canvas.height-((cardHeight*2) * handScale)-30
+ ];
+
+ gameData.size[key] = [cardWidth * handScale, cardHeight * handScale];
+
+ break;
+
+ // Opponent
+ case gameData.opponentId:
+
+ cardsOnBoard = gameData.cardCount.board[gameData.opponentId];
+ position = gameData.listPosition[key];
+
+ gameData.position[key] = [
+ canvas.width/2 - (cardWidth * (cardsOnBoard - (position+1)) - (cardMargin * (position+1)))
+ ,((cardHeight*2) * handScale)+30
+ ];
+ gameData.size[key] = [cardWidth * handScale, cardHeight * handScale];
+
+ break;
+
+ }
+ }
+
}
// TODO: Move this function elsewhere, not really a draw function
function calculateCardSpacing(positionInt, size, standardSize){
@@ -129,6 +174,11 @@ function drawEntities(){
drawCardInHand(key);
}
+ // If card on board
+ if(key in gameData.board){
+ drawCardOnBoard(key);
+ }
+
if(key in gameData.inInteractionMenu){
// Add the menu with 'play', 'activate effect', 'inspect', etc.
drawInteractionMenu(key);
@@ -168,10 +218,27 @@ function drawDeck(entity){
}
function drawCardInHand(entity){
- // TODO: Tapped, Attacking, Targettable, Activatable borders
-
// TODO: Change card colour based on its colours
- // TODO: Not for hand, but cards on board need flight, etc.
+
+ // Draw the card shape
+ let shape = new Shape({
+ x: gameData.position[entity][0],
+ y: gameData.position[entity][1],
+ width: gameData.size[entity][0],
+ height: gameData.size[entity][1],
+ fillStyle: '#EEE',
+ strokeStyle: '#AAA',
+ });
+ shape.draw();
+
+ drawCardDetails(entity);
+
+}
+
+function drawCardOnBoard(entity){
+
+ // TODO: Tapped, Attacking, Targettable, Activatable borders
+ // TODO: Passives, flight, etc. effects
// Draw the card shape
let shape = new Shape({
@@ -261,29 +328,36 @@ function drawCardText(entity){
// so TODO gotta make it scaled % wise with the 80/16 I wrote above
// NAME
+ if(gameData.cardData[entity] !== undefined && gameData.cardData[entity]['name'] !== undefined){
printText(gameData.cardData[entity]['name']
, positionX + 5 + 10 // + 5 (spacing for cost) + 10 for more spacing
, positionY + 10 + 5 // + 10pt + 5 as it's the spacing I actually want
, 'left', 'alphabetic', 'normal', 'normal', fontSize, 'Arial', fillStyle, strokeStyle, strokeSize, false
);
+ }
// COST
+ if(gameData.cardData[entity] !== undefined && gameData.cardData[entity]['cost'] !== undefined){
printText(gameData.cardData[entity]['cost']
, positionX + 5
, positionY + 10 + 5 // + 10pt + 5 as it's the spacing I actually want
, 'left', 'alphabetic', 'normal', 'normal', fontSize, 'Arial', fillStyle, strokeStyle, strokeSize, false
);
+ }
// TYPE
+ if(gameData.cardData[entity] !== undefined && gameData.cardData[entity]['type'] !== undefined){
printText(
CLASS[gameData.cardData[entity]['type']]
, positionX + 5
, positionY + width // To be slightly over bottom of image (which uses width to position)
, 'left', 'alphabetic', 'normal', 'normal', fontSize, 'Arial', fillStyle, strokeStyle, strokeSize, false
);
+ }
// CLASS(ES)
+ if(gameData.cardData[entity] !== undefined && gameData.cardData[entity]['class'] !== undefined){
let classes = '';
// Loop the classes, and add each of them to the card
for(let i = 0; i < gameData.cardData[entity]['class'].length; i++){
@@ -299,8 +373,10 @@ function drawCardText(entity){
, positionY + width // To be slightly over bottom of image (which uses width to position)
, 'left', 'alphabetic', 'normal', 'normal', fontSize, 'Arial', fillStyle, strokeStyle, strokeSize, false
);
+ }
// EFFECT(S)
+ if(gameData.cardData[entity] !== undefined && gameData.cardData[entity]['effect'] !== undefined){
// TODO: Split the text onto lines based on character count (but not splitting words) so they fit into the
// bounds of the card element
let effects = '';
@@ -317,13 +393,16 @@ function drawCardText(entity){
, positionY + width + 10 // To be beneath image, and type + classes
, 'left', 'alphabetic', 'normal', 'normal', fontSize, 'Arial', fillStyle, strokeStyle, strokeSize, false
);
+ }
// ATTACK
+ if(gameData.cardData[entity] !== undefined && gameData.cardData[entity]['attack'] !== undefined){
printText(gameData.cardData[entity]['attack']
, positionX + width/2 - ctx.measureText(gameData.cardData[entity]['attack']).width/2 // Should be centred
, positionY + 10 + (height - 10) // + 10pt + 5 as it's the spacing I actually want
, 'left', 'alphabetic', 'normal', 'normal', fontSize, 'Arial', fillStyle, strokeStyle, strokeSize, false
);
+ }
// Reset font for other draws
// TODO: Probably just use a save/restore for the font draws in here
@@ -477,3 +556,11 @@ function drawInteractionMenu(entity){
}
+// TODO: Put the stack into the UI
+function drawStackResolve(){
+
+}
+// TODO: Draw stack, all cards in the stack in order (use the cardId for display)
+// make inspectable, and display which part of the effect will be triggered in it's
+// stack position
+
diff --git a/public/js/canvas/interaction.js b/public/js/canvas/interaction.js
index d70b504..208c82e 100644
--- a/public/js/canvas/interaction.js
+++ b/public/js/canvas/interaction.js
@@ -69,6 +69,8 @@ canvas.addEventListener('click', function(event) {
console.log(key);
+ // After an interaction, clear the menu to prevent redraw
+ clearInteractionMenu();
// Then return true to prevent another interaction
return true;
}
diff --git a/public/js/game/components.js b/public/js/game/components.js
index bfd019b..3dd9e62 100644
--- a/public/js/game/components.js
+++ b/public/js/game/components.js
@@ -15,6 +15,7 @@ let gameData = {
cardCount : {
deck : {},
hand : {},
+ board : {},
},
inInteractionMenu : {},
@@ -27,6 +28,7 @@ let gameData = {
player : {},
deck : {},
hand : {},
+ board : {},
// 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 60508c1..106906b 100644
--- a/public/js/game/dataUpdate.js
+++ b/public/js/game/dataUpdate.js
@@ -59,8 +59,36 @@ function updatePlayerHand(data){
// Likely to union all the data server-side and pass as one
// function such as updateEntities() or something
gameData.hand = data.handEntities;
- gameData.listPosition = data.handPositions;
- gameData.cardData = data.handCardData;
+ gameData.listPosition = data.handPositions; // Change to all listPositions
+ gameData.cardData = data.handCardData; // Changed to all cardData
+ // Changes made here, as when drawing a card updateBoard data was wiped and caused
+ // 'undefined' listPositions and other data...
+}
+
+function updateBoard(data){
+ // TODO: ONLY RETURN NEEDED DATA
+ // AND ONLY UPDATE NEEDED DATA
+ // TODO: Currently everything is being passed
+ // which is 1 slow, and 2 bad because it gives players
+ // too much information, they only need what's to be
+ // drawn and interacted with
+ console.log('TODO: updateBoard correctly');
+ console.log(data);
+ gameData.board = data.board;
+ gameData.passive = data.passive;
+ gameData.listPosition = data.listPosition
+ gameData.cardData = data.cardData;
+ gameData.cardCost = data.cardCost;
+ gameData.cardColours = data.cardColours;
+ //console.log(data);
+}
+
+// To prevent typical functionality (draw, etc.)
+// if there's a stack in play.
+// TODO: Can only chain the stack or resolve it
+function updateStack(data){
+ alert('You must resolve the stack, or chain an effect');
+ console.log(data);
console.log(gameData);
}
diff --git a/public/js/game/socket.js b/public/js/game/socket.js
index 3f1fac1..5b6a016 100644
--- a/public/js/game/socket.js
+++ b/public/js/game/socket.js
@@ -18,13 +18,18 @@ function requestDrawACard(){
console.log('>> drawACard');
socket.emit('drawACard', gameData.roomId, gameData.playerId);
}
-// Draw Card
// Both players get new hand + deck counts updated
socket.on('responseDrawCard', function (data) {
console.log('<< drawCard');
updateCardCount(data);
drawGameBoard();
});
+socket.on('responseCardCounts', function (data) {
+ console.log('<< responseCardCounts');
+ updateCardCount(data);
+ drawGameBoard();
+});
+
// Player drew card
// Player that drew the card (atm) gets the cardData, listPosition
@@ -36,6 +41,12 @@ socket.on('responsePlayerDrewCard', function (data) {
});
+socket.on('responseUpdateBoard', function (data) {
+ console.log('<< updateBoard');
+ updateBoard(data);
+ drawGameBoard();
+});
+
// SHUFFLE DECK
function requestShuffleDeck(){
console.log('>> shuffleDeck');
@@ -58,9 +69,38 @@ function requestPlayFromHand(listPosition){
socket.emit('playFromHand', gameData.roomId, gameData.playerId, listPosition);
}
socket.on('responsePlayFromHand', function (data) {
+ // Return boardData, update hand
console.log('<< playFromHand');
+ console.log(data);
});
+// Stack
+socket.on('responseAddToStack', function (data) {
+ console.log('<< addToStack');
+ console.log(data);
+});
+socket.on('responseResolveStack', function (data) {
+ console.log('<< resolveStack _x_');
+ console.log(data);
+ drawGameBoard();
+});
+socket.on('responseRemoveFromStack', function (data) {
+ console.log('<< removeFromStack ?');
+ console.log(data);
+});
+// All players need to accept the stack 'resolve' before it'll occur
+socket.on('responseGetStackResponse', function (data) {
+ // TODO: Return all valid effect triggers/responses to the effect trigger
+ // on the top of the stack, and a 'resolve' option to not trigger anything
+ console.log('<< getStackResponse');
+ updateStack(data);
+});
+function requestResolveStack(){
+ // This is just for 'resolve' press. Not playing atop the stack.
+ console.log('>> requestResolveStack');
+ socket.emit('requestResolveStack', gameData.roomId, gameData.playerId);
+}
+
// 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 d543604..7efc4d8 100644
--- a/server.js
+++ b/server.js
@@ -66,6 +66,11 @@ function onConnection(socket){
socket.on('playFromHand', function(roomId, playerId, listPosition) {
gameMod.playFromHand(roomId, playerId, listPosition);
});
+
+ socket.on('requestResolveStack', function(roomId, playerId) {
+ gameMod.acceptResolveStack(roomId, playerId);
+ console.log('resolve stack yep yep yep');
+ });
}
@@ -116,20 +121,26 @@ global.socketResponseDrawCard = function(roomId, playerId){
console.log('>> '+roomData[roomId].playerData[playerId].playerId+' drew card');
- global.socketReturnCardCounts(roomId);
+ global.socketReturnCardCounts(roomId, 'responseDrawCard');
}
-global.socketReturnCardCounts = function(roomId){
+global.socketReturnCardCounts = function(roomId, responseName = 'responseCardCounts'){
let data = global.roomData[roomId].itemData.component.cardCount;
- global.sendToEachSocket(roomId, 'responseDrawCard', data);
+ global.sendToEachSocket(roomId, responseName, data);
}
global.socketResponsePlayerDrewCard = function(roomId, playerId){
+ global.socketResponsePlayerHandData(roomId, playerId);
+
+}
+
+global.socketResponsePlayerHandData = function(roomId, playerId){
+
// This function may be redundant fast, as hand, board, grave, void
// anywhere that's visible to one (or both) players will need all the data
// sending, so will likely be one function that returns it all?
@@ -150,6 +161,17 @@ global.socketResponseShuffleDeck = function(roomId, playerId, hasShuffled){
}
+global.socketResponseUpdateBoard = function(roomId){
+
+ // TODO: Only return the data that's needed, no everything
+ let data = global.roomData[roomId].itemData.component;
+ // Return the data on the board (to both players)
+ // TODO: If card flips/face-downs are to be a thing, only return the cardData, etc.
+ // to the player who's side it's on
+ global.sendToEachSocket(roomId, 'responseUpdateBoard', data);
+
+}
+
global.socketResponsePlayFromHand = function(roomId, playerId, cardId){
console.log('>> '+roomData[roomId].playerData[playerId].playerId+' played from hand');
@@ -157,8 +179,28 @@ global.socketResponsePlayFromHand = function(roomId, playerId, cardId){
// 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
+ // Update hand of player that card's hand was played from (using existing logic)
+ global.socketResponsePlayerHandData(roomId, playerId);
+
+ // Update the board (for both players)
+ global.socketResponseUpdateBoard(roomId);
+
+ // So the animations can be played with the new cardData (in future)
global.sendToEachSocket(roomId, 'responsePlayFromHand', cardId);
+}
+
+// Stack
+global.socketResponseAddToStack = function(roomId){
+ global.sendToEachSocket(roomId, 'responseAddToStack', 'testData');
+}
+global.socketResponseResolveStack = function(roomId){
+ global.sendToEachSocket(roomId, 'responseResolveStack', 'testData');
+}
+// TODO: Each player one at a time to prevent just self-chaining 24/7
+global.socketGetStackResponse = function(roomId){
+ // TODO: Return all valid effect triggers/responses to the effect trigger
+ // on the top of the stack, and a 'resolve' option to not trigger anything
+ global.sendToEachSocket(roomId, 'responseGetStackResponse', 'testData');
}