From f753d5d3df9cbf5a34f654406580cdca92fd1b52 Mon Sep 17 00:00:00 2001 From: Nathan Date: Thu, 10 Oct 2024 18:36:17 +0100 Subject: [PATCH 01/41] Add beginning of DO/ECS --- public/board.js | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/public/board.js b/public/board.js index dc20c75..e08064c 100644 --- a/public/board.js +++ b/public/board.js @@ -15,7 +15,19 @@ clickableItems['board'] = []; clickableItems['hand'] = []; clickableItems['opponentHand'] = []; -// TODO: Uniform the arrays to player and opponent/different playesr +// Array of items, the 'Entity Manager' as such +let item = []; +let itemCount = 0; +// Component 1: Where on the board, hand, deck, mana, shield, etc. +// send back item, itemCount and individual comp. from server? +let boardElement = {}; +let cardData = {}; +let position = {}; +let size = {}; +//let shape = {}; +let cardStatus = {}; // tapped, attacking, inspected, untargettable +let player = {}; + let playerHand = []; let opponentHand = []; let playerBoard = []; @@ -421,7 +433,6 @@ class Board{ this.drawBoard(); } playCardToBoardFromDeckOpponent(){ - // Random card from deck let cardToDraw = Math.floor(Math.random() * deckCount); let cardPlayed = opponentDeck[cardToDraw]; @@ -641,8 +652,8 @@ class Board{ } // TEMP!! -createDeckList(playerDeck, deckCount); -createDeckList(opponentDeck, deckCountOpponent); +createDeckList(playerDeck, deckCount, 0); +createDeckList(opponentDeck, deckCountOpponent, 1); // Run board commands here for testing let board = new Board; @@ -821,14 +832,17 @@ function clickableCheck(x,y,clickable){ // TEMP: Create a deck of X different cards that can be drawn/played // for UI development, will be done on server and not shown to clients -function createDeckList(deck, deckCount){ +function createDeckList(deck, deckCount, playerId){ for(let i = 0; i < deckCount; i++){ // Randomise colour let colour = Math.floor(Math.random() * 2); let effect = Math.floor(Math.random() * 5); if(effect == 0){ effect = 'effect here'; } else{ effect = null } - deck.push({ + + item.push[itemCount]; + boardElement[itemCount] = 'deck'; + cardData[itemCount] = { 'name':'CardName '+(i+1) , 'cost':1 , 'atk':1 @@ -838,7 +852,12 @@ function createDeckList(deck, deckCount){ , 'type':'human' , 'colour':colour , 'tapped':false - }); + }; + player[playerId]; + // Previous iteration, kept to prevent errors for now + deck.push(cardData[itemCount]); + + itemCount++; } } From 59a66146073cb59696a19aa7f90dd3ce98022403 Mon Sep 17 00:00:00 2001 From: Nathan Date: Thu, 10 Oct 2024 20:11:57 +0100 Subject: [PATCH 02/41] Add listPosition component, and shuffle mechanic --- public/board.js | 59 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/public/board.js b/public/board.js index e08064c..41f5935 100644 --- a/public/board.js +++ b/public/board.js @@ -27,6 +27,7 @@ let size = {}; //let shape = {}; let cardStatus = {}; // tapped, attacking, inspected, untargettable let player = {}; +let listPosition = {}; let playerHand = []; let opponentHand = []; @@ -433,6 +434,27 @@ class Board{ this.drawBoard(); } playCardToBoardFromDeckOpponent(){ + + // Loop items for opponent deck. boardElement = deck, and player = 1 + for(let itemKey = 0; itemKey < item.length; itemKey++){ + // Check if item is in deck + // 'key' in 'object' + if(itemKey in boardElement && boardElement[itemKey] == 'deck'){ + // Check if item belongs to opponent + if(itemKey in player && player[itemKey] == 1){ + // Check list position for top of deck + } + } + } + // Select card from top of deck? + // Switch the item boardElement from deck->board + // not for here: if player = 1 and boardElement = board draw it + // + + + + + // Random card from deck let cardToDraw = Math.floor(Math.random() * deckCount); let cardPlayed = opponentDeck[cardToDraw]; @@ -658,6 +680,8 @@ createDeckList(opponentDeck, deckCountOpponent, 1); // Run board commands here for testing let board = new Board; //board.initBoard(); +shuffleDeck(0); +shuffleDeck(1); // TEMP: Play a card on opponents board (from their deck) board.playCardToBoardFromDeckOpponent(); @@ -840,7 +864,7 @@ function createDeckList(deck, deckCount, playerId){ if(effect == 0){ effect = 'effect here'; } else{ effect = null } - item.push[itemCount]; + item.push(itemCount); boardElement[itemCount] = 'deck'; cardData[itemCount] = { 'name':'CardName '+(i+1) @@ -853,7 +877,8 @@ function createDeckList(deck, deckCount, playerId){ , 'colour':colour , 'tapped':false }; - player[playerId]; + player[itemCount] = playerId; + listPosition[itemCount] = i; // Previous iteration, kept to prevent errors for now deck.push(cardData[itemCount]); @@ -861,6 +886,36 @@ function createDeckList(deck, deckCount, playerId){ } } +function shuffleDeck(playerId){ + let tempDeck = []; + for(let itemKey = 0; itemKey < item.length; itemKey++){ + // Check if item is in deck + // 'key' in 'object' + if(itemKey in boardElement && boardElement[itemKey] == 'deck'){ + // Check if item belongs to opponent + if(itemKey in player && player[itemKey] == playerId){ + // This will shuffle, but not from OG deck state. + // Will need to get the listPosition and order by that first + console.log(itemKey); + tempDeck.push(itemKey); + } + } + } + + // Temporary shuffle until algo selected/written + let id, shuffledPile, i; + for (i = tempDeck.length - 1; i > 0; i--) { + id = Math.floor(Math.random() * (i + 1)); + //shuffledPile = tempDeck[i]; + //tempDeck[i] = tempDeck[id]; + //tempDeck[id] = shuffledPile; + + // Change the position within the deck + listPosition[tempDeck[id]] = i; + } + +} + function untap(array){ console.log(array); array.forEach(function(card, key){ From 158bd627c7cfcc743e06a779fc3f7b63b32c1835 Mon Sep 17 00:00:00 2001 From: Nathan Date: Fri, 11 Oct 2024 14:33:07 +0100 Subject: [PATCH 03/41] Add OppBoard, and draw using itemdata --- public/board.js | 132 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 107 insertions(+), 25 deletions(-) diff --git a/public/board.js b/public/board.js index 41f5935..33e1bd7 100644 --- a/public/board.js +++ b/public/board.js @@ -85,6 +85,8 @@ class Board{ this.drawPlayerNames('Nathan', 'Evil Nathan'); + this.drawCardsECS(); // Atop most everything atm for testing + if(gameWin){ this.drawWin(); } @@ -122,6 +124,61 @@ class Board{ } } + drawCardsECS(){ + // Loop all items + for(let itemKey = 0; itemKey < item.length; itemKey++){ + // Check if item is not in deck, deck items aren't to be drawn + // 'key' in 'object' + if(itemKey in boardElement && boardElement[itemKey] != 'deck'){ + // Check if item belongs to opponent for now + // this will just be used to set positioning in the future + if(itemKey in player && player[itemKey] == 1){ + // Just for opponentBoard atm + // This method will need to draw all cards, calcing their positions + // Which sounds hard + let opponentBoardLength = getCurrentPositionAndLength('board', 1)[1]; + + // I know it's redundant, just need to get my head around it all + // Setting position, will be moved elsewhere when working fully + let cardPadding = 10; + let i = listPosition[itemKey]; + console.log('cardName: '+cardData[itemKey].name); + console.log('i/listPosition: '+i); + console.log('boardLength: '+opponentBoardLength); + let positionX = canvas.width/2 - (cardWidth * (opponentBoardLength - i) - (cardPadding * i)); + console.log('posX: '+positionX); + let positionY = cardHeight + 30; + let width = cardWidth; + let height = cardHeight; + + position[itemKey] = [positionX,positionY]; + size[itemKey] = [width, height]; + + // Check status (for tapped atm) + let border = null; + if(cardStatus[itemKey] == 'tapped'){border = '#E0BC00';} + let name = itemKey; // Not needed really anymore, but keeping for now + positionX = position[itemKey][0]; + positionY = position[itemKey][1]; + width = size[itemKey][0]; + height = size[itemKey][1]; + let fill = '#CCC'; + + let shape = new Shape({ + name: name, + x: positionX, + y: positionY, + width: width, + height: height, + fillStyle: fill, + strokeStyle: border + }); + + shape.draw(); + } + } + } + } // Draw Invidual Cards, called by other deck stuff // Might be put into a card class, makes sense, eh. drawCard(array, arrayKey, name, positionX, positionY, width, height, fill, border){ @@ -364,6 +421,8 @@ class Board{ } drawCardsOnBoardOpponent(){ + // OLD, being rewritten + if(true){ for (let i = 0; i < opponentBoard.length; i++) { let name = 'cardOnBoardOpponent_'+(i+1); @@ -379,6 +438,7 @@ class Board{ this.drawCard(opponentBoard, i, name, positionX, positionY, width, height, fill); } + } } // Currently only functionality in hand @@ -435,6 +495,11 @@ class Board{ } playCardToBoardFromDeckOpponent(){ + if(opponentBoard.length >= maxBoardSize){ + alert('No space on board to play card. '+opponentBoard.length+'/'+maxBoardSize); + return 0; + } + // Loop items for opponent deck. boardElement = deck, and player = 1 for(let itemKey = 0; itemKey < item.length; itemKey++){ // Check if item is in deck @@ -443,31 +508,19 @@ class Board{ // Check if item belongs to opponent if(itemKey in player && player[itemKey] == 1){ // Check list position for top of deck + if(listPosition[itemKey] == 0){ + // Set the new position (on board) + listPosition[itemKey] = getCurrentPositionAndLength('board', 1)[0]+1 + // Move from current item to board + boardElement[itemKey] = 'board'; + } + else{ + // Move all other items in deck down in position by 1 to get new 0 + listPosition[itemKey]--; + } } } } - // Select card from top of deck? - // Switch the item boardElement from deck->board - // not for here: if player = 1 and boardElement = board draw it - // - - - - - - // Random card from deck - let cardToDraw = Math.floor(Math.random() * deckCount); - let cardPlayed = opponentDeck[cardToDraw]; - - if(opponentBoard.length >= maxBoardSize){ - alert('No space on board to play card. '+opponentBoard.length+'/'+maxBoardSize); - return 0; - } - - // Remove from deck - opponentDeck.splice(cardToDraw, 1); - // Add to board - opponentBoard.push(cardPlayed); this.drawBoard(); } @@ -680,11 +733,12 @@ createDeckList(opponentDeck, deckCountOpponent, 1); // Run board commands here for testing let board = new Board; //board.initBoard(); -shuffleDeck(0); -shuffleDeck(1); +//shuffleDeck(0); +//shuffleDeck(1); // TEMP: Play a card on opponents board (from their deck) board.playCardToBoardFromDeckOpponent(); +board.playCardToBoardFromDeckOpponent(); board.drawBoard(); @@ -896,7 +950,7 @@ function shuffleDeck(playerId){ if(itemKey in player && player[itemKey] == playerId){ // This will shuffle, but not from OG deck state. // Will need to get the listPosition and order by that first - console.log(itemKey); + //console.log(itemKey); tempDeck.push(itemKey); } } @@ -904,6 +958,7 @@ function shuffleDeck(playerId){ // Temporary shuffle until algo selected/written let id, shuffledPile, i; + console.log(tempDeck.length); for (i = tempDeck.length - 1; i > 0; i--) { id = Math.floor(Math.random() * (i + 1)); //shuffledPile = tempDeck[i]; @@ -928,4 +983,31 @@ function untapAll(){ untap(playerBoard); untap(opponentShield); } +function getCurrentPositionAndLength(elementName, playerId){ + + let highestListPosition = 0; + let length = 0; + // Loop all the items + // Think making the for loop, and the if into something to be called that fires functions would be smart? + for(let itemKey = 0; itemKey < item.length; itemKey++){ + // Check the item is the correct boardElement + // 'key' in 'object' + if(itemKey in boardElement && boardElement[itemKey] == elementName){ + // Check if item belongs to the player + if(itemKey in player && player[itemKey] == playerId){ + + if(listPosition[itemKey]){ + if(listPosition[itemKey] >= highestListPosition){ + highestListPosition = listPosition[itemKey]; + length++; + } + } + + } + } + } + + return [highestListPosition, length]; + +} From c3da40df0e96a729d5f0d53dd096d3af8fd8e89f Mon Sep 17 00:00:00 2001 From: Nathan Date: Fri, 11 Oct 2024 15:13:06 +0100 Subject: [PATCH 04/41] Move oppBoard draw into a non-specific loop This should allow to draw all elements from the same loop and avoid loads of scattered methods for draw. 1 draw method, other methods for real functionality --- public/board.js | 49 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/public/board.js b/public/board.js index 33e1bd7..6d50337 100644 --- a/public/board.js +++ b/public/board.js @@ -15,6 +15,11 @@ clickableItems['board'] = []; clickableItems['hand'] = []; clickableItems['opponentHand'] = []; +// Counters to keep track of players, and boardElements, may be changed in future +// But once game starts, will be const anyway, so shouldn't need passing +let players = 2; // Player, Opponent for now, but will be up to 6 players for 5v1 boss raids? +let elements = ['deck','board','hand','mana','shield']; +let elementsSizes = {}; // May need to have the base XY WH of board, hand, etc. stored for loop draw // Array of items, the 'Entity Manager' as such let item = []; let itemCount = 0; @@ -125,28 +130,37 @@ class Board{ } drawCardsECS(){ + // ALL NON DECK CARDS DO BE DRAWN IN SAME LOOP (ideally) // Loop all items for(let itemKey = 0; itemKey < item.length; itemKey++){ - // Check if item is not in deck, deck items aren't to be drawn - // 'key' in 'object' - if(itemKey in boardElement && boardElement[itemKey] != 'deck'){ - // Check if item belongs to opponent for now - // this will just be used to set positioning in the future - if(itemKey in player && player[itemKey] == 1){ - // Just for opponentBoard atm - // This method will need to draw all cards, calcing their positions - // Which sounds hard - let opponentBoardLength = getCurrentPositionAndLength('board', 1)[1]; - // I know it's redundant, just need to get my head around it all - // Setting position, will be moved elsewhere when working fully + // Loop each element, and player + for(let elementCount in elements){ + + // Don't draw deck TODO:/gy/void + // TODO: Unless inspecting + let element = elements[elementCount]; + if(element == 'deck'){ + continue; + } + + // Draw Elements + // Loop each item left, and draw if element is currently looped. board,mana,etc. + if(itemKey in boardElement && boardElement[itemKey] == element){ + // Get the player the item belongs to + let itemPlayer = player[itemKey]; + console.log('Element: '+element+', Player: '+itemPlayer); + + // Calc position of the element draw + let itemListPositionLength = getCurrentPositionAndLength(element, 1); + let itemListPositionNext = itemListPositionLength[0]; + let itemListLength = itemListPositionLength[1]; + let cardPadding = 10; let i = listPosition[itemKey]; - console.log('cardName: '+cardData[itemKey].name); - console.log('i/listPosition: '+i); - console.log('boardLength: '+opponentBoardLength); - let positionX = canvas.width/2 - (cardWidth * (opponentBoardLength - i) - (cardPadding * i)); - console.log('posX: '+positionX); + console.log('cardName: '+cardData[itemKey].name+', i/listPosition: '+i+', listPosition Length: '+itemListLength); + + let positionX = canvas.width/2 - (cardWidth * (itemListLength - i) - (cardPadding * i)); let positionY = cardHeight + 30; let width = cardWidth; let height = cardHeight; @@ -175,6 +189,7 @@ class Board{ }); shape.draw(); + } } } From b0b784c619c73937c2b4cf52ad67909d08c3ae43 Mon Sep 17 00:00:00 2001 From: Nathan Date: Fri, 11 Oct 2024 16:00:36 +0100 Subject: [PATCH 05/41] Add all current drawing into drawECS loop This is working well, drawing everything with only needing to pass the item key --- public/board.js | 182 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 144 insertions(+), 38 deletions(-) diff --git a/public/board.js b/public/board.js index 6d50337..042a3aa 100644 --- a/public/board.js +++ b/public/board.js @@ -151,49 +151,126 @@ class Board{ let itemPlayer = player[itemKey]; console.log('Element: '+element+', Player: '+itemPlayer); - // Calc position of the element draw - let itemListPositionLength = getCurrentPositionAndLength(element, 1); - let itemListPositionNext = itemListPositionLength[0]; - let itemListLength = itemListPositionLength[1]; - - let cardPadding = 10; - let i = listPosition[itemKey]; - console.log('cardName: '+cardData[itemKey].name+', i/listPosition: '+i+', listPosition Length: '+itemListLength); - - let positionX = canvas.width/2 - (cardWidth * (itemListLength - i) - (cardPadding * i)); - let positionY = cardHeight + 30; - let width = cardWidth; - let height = cardHeight; - - position[itemKey] = [positionX,positionY]; - size[itemKey] = [width, height]; - - // Check status (for tapped atm) - let border = null; - if(cardStatus[itemKey] == 'tapped'){border = '#E0BC00';} - let name = itemKey; // Not needed really anymore, but keeping for now - positionX = position[itemKey][0]; - positionY = position[itemKey][1]; - width = size[itemKey][0]; - height = size[itemKey][1]; - let fill = '#CCC'; - - let shape = new Shape({ - name: name, - x: positionX, - y: positionY, - width: width, - height: height, - fillStyle: fill, - strokeStyle: border - }); - - shape.draw(); + calculateItemSizePosition(itemKey); + this.printCardToCanvas(itemKey); } } } } + + printCardToCanvas(itemKey){ + // If the itemKey has cardData, position, size, and boardElement we can draw it + // TODO: Add a check for error handling + + // Check status, and change border colour for display (for tapped atm) + let border = null; + if(cardStatus[itemKey] == 'tapped'){border = '#E0BC00';} + + // Set the card 'cardboard' colour based on the card colour type + let colourId = cardData[itemKey].colour; + let fill = null; + if(colourId == 0){ fill = '#EEE'; } + else if(colourId == 1){ fill = '#0033EE'; } + + let name = itemKey; // Not needed really anymore, but keeping for now + let positionX = position[itemKey][0]; + let positionY = position[itemKey][1]; + let width = size[itemKey][0]; + let height = size[itemKey][1]; + + // Draw the card shape itself + let shape = new Shape({ + name: name, + x: positionX, + y: positionY, + width: width, + height: height, + fillStyle: fill, + strokeStyle: border + }); + shape.draw(); + + this.printCardImage(itemKey); + + this.printCardDetails(itemKey); + + + } + + printCardImage(itemKey){ + let name = itemKey; // Not needed really anymore, but keeping for now + let positionX = position[itemKey][0]; + let positionY = position[itemKey][1]; + let width = size[itemKey][0]; + let height = size[itemKey][1]; + let fill = '#BBB'; + let shape = 'semi'; // Will be decided based on cardData.something? (for unit, spell, etc) + + // Add 'image' shape, will need to blitz sprite here in the future (based on cardData.id) + let cardImageContainer = new Shape({ + shape: 'semi', + name: 'cardImageContainer_'+name, + x: positionX+height/3, + y: positionY+width/2, + width: width*.9, + height: height*.9, + fillStyle: fill + }); + cardImageContainer.draw(); + + // Draw the actual image too + + } + printCardDetails(itemKey){ + let name = itemKey; // Not needed really anymore, but keeping for now + let positionX = position[itemKey][0]; + let positionY = position[itemKey][1]; + let width = size[itemKey][0]; + let height = size[itemKey][1]; + + // Add card name + let fontSize = width/cardWidth*10; // 10 = baseFontSize of 10pt + ctx.font = "bold "+fontSize+"pt Arial"; + ctx.fillStyle = '#000'; + ctx.fillText( + cardData[itemKey]['name'] + , positionX + (ctx.measureText(cardData[itemKey]['name']/2).width) - width/4 + , positionY+height*.25 + ); + + // Add card type + ctx.fillText( + cardData[itemKey]['type'] + , positionX + (ctx.measureText(cardData[itemKey]['type']/2).width) - width/4 + , positionY+height*.7 + ); + // Add text/effect area + if(cardData[itemKey]['effect'] !== null){ + ctx.fillText( + cardData[itemKey]['effect'] + , positionX + (ctx.measureText(cardData[itemKey]['effect']/2).width) - width/4 + , positionY+height*.8 + ); + } + // Attack + ctx.fillText( + cardData[itemKey]['atk'] + , positionX + (ctx.measureText(cardData[itemKey]['atk']).width) + , positionY+height*.95 + ); + // Add cost + ctx.fillText( + cardData[itemKey]['cost'] + , positionX + (ctx.measureText(cardData[itemKey]['cost']).width) + , positionY+height*.1 + ); + + // Unbold font for other draws + ctx.font = "10pt Arial"; + } + + // Draw Invidual Cards, called by other deck stuff // Might be put into a card class, makes sense, eh. drawCard(array, arrayKey, name, positionX, positionY, width, height, fill, border){ @@ -1026,3 +1103,32 @@ function getCurrentPositionAndLength(elementName, playerId){ } +function calculateItemSizePosition(itemKey){ + + // Calc position and size of the item + // Used for drawing and interacting + + let itemPlayer = player[itemKey]; + let itemElement = boardElement[itemKey]; + + let itemListPositionLength = getCurrentPositionAndLength(itemElement, itemPlayer); + let itemListPositionNext = itemListPositionLength[0]; + let itemListLength = itemListPositionLength[1]; + + // TODO:Padding probably will differ between elements + let cardPadding = 10; + let i = listPosition[itemKey]; + //console.log('cardName: '+cardData[itemKey].name+', i/listPosition: '+i+', listPosition Length: '+itemListLength); + + // TODO:X/Y W/H 100% differs based on the element + let positionX = canvas.width/2 - (cardWidth * (itemListLength - i) - (cardPadding * i)); + let positionY = cardHeight + 30; + let width = cardWidth; + let height = cardHeight; + + // Set the size/position of the item + size[itemKey] = [width, height]; + position[itemKey] = [positionX,positionY]; + +} + From 85b0704a4efb1fa3a2fd7a65433aa312117e108b Mon Sep 17 00:00:00 2001 From: Nathan Date: Fri, 11 Oct 2024 16:42:14 +0100 Subject: [PATCH 06/41] Add item size and position to eventHandler --- public/board.js | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/public/board.js b/public/board.js index 042a3aa..61fd6c9 100644 --- a/public/board.js +++ b/public/board.js @@ -880,6 +880,32 @@ canvas.addEventListener('click', function(event) { var x = event.pageX - canvasLeft, y = event.pageY - canvasTop; + + // Check clicks against itemKey position+size + // Will be the new way + // TODO:Maybe write this into a function? If XY WH is hit return true, and the itemKey + // then it can be re-used in contextclick, hover, etc without rewrite + //console.log('X: '+x+' Y: '+y); + for(let itemKey = 0; itemKey < item.length; itemKey++){ + + if(elements[itemKey] == 'deck'){ + continue; + } + + // Check the item has a size and position + if(itemKey in size && itemKey in position){ + // Compare the event XY position to the item + if(clickableCheck(x,y,false,itemKey)){ + cardStatus[itemKey] = 'tapped'; + } + } + + board.drawBoard(); + + } + + + // Collision detection between clicked offset and clickableItems // https://stackoverflow.com/a/9880302 @@ -979,7 +1005,20 @@ canvas.addEventListener('click', function(event) { }, false); -function clickableCheck(x,y,clickable){ +function clickableCheck(x,y,clickable=false,itemKey=false){ + + // Temp solution to add the check while the old way also exists + // simultaneously. It works, so that's nice + if(clickable === false && itemKey !== false){ + clickable = {}; + console.log(clickable); + console.log(itemKey); + clickable.x = position[itemKey][0]; + clickable.y = position[itemKey][1]; + clickable.width = size[itemKey][0]; + clickable.height = size[itemKey][1]; + console.log(clickable); + } // Debug Stuff let debug = false From 9569dc8320247c032e3d86312d86f5932195242b Mon Sep 17 00:00:00 2001 From: Nathan Date: Fri, 11 Oct 2024 23:28:01 +0100 Subject: [PATCH 07/41] Add switch boardElement, and draw loop for ECS --- public/board.js | 140 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 131 insertions(+), 9 deletions(-) diff --git a/public/board.js b/public/board.js index 61fd6c9..0a9164d 100644 --- a/public/board.js +++ b/public/board.js @@ -45,6 +45,9 @@ let opponentShield = []; let playerMana = []; let opponentManaZone = []; +// To disable drawing each time something changes +let drawEachEvent = true; + let deckCount = 60; let deckCountOpponent = 60; @@ -68,7 +71,10 @@ class Board{ ctx.fillStyle = '#000'; } - drawBoard(){ + drawBoard(force = false){ + if(drawEachEvent == false && force == false){ + return 0; + } // Reset board ctx.clearRect(0, 0, canvas.width, canvas.height); // Room Name @@ -147,6 +153,9 @@ class Board{ // Draw Elements // Loop each item left, and draw if element is currently looped. board,mana,etc. if(itemKey in boardElement && boardElement[itemKey] == element){ + if(boardElement[itemKey] == 'hand' && player[itemKey] == 0){ + console.log('PLAYER HAND'); + } // Get the player the item belongs to let itemPlayer = player[itemKey]; console.log('Element: '+element+', Player: '+itemPlayer); @@ -452,8 +461,91 @@ class Board{ drawCards(){} + addFromBoardElement(playerFrom, fromPosition, elementFrom, elementTo, toPosition=null, playerTo=null){ + if(playerTo == null){ + playerTo = playerFrom; + } + + // Move itemKey fromPosition in elementFrom to toPosition in elementTo + // Can also switch item between players + + for(let itemKey = 0; itemKey < item.length; itemKey++){ + // Get the item from the element + if(itemKey in boardElement && boardElement[itemKey] == elementFrom){ + // Check if item belongs to playerFrom + if(itemKey in player && player[itemKey] == playerFrom){ + + // Get item based on fromPosition listPosition + if(listPosition[itemKey] == fromPosition){ + // Check if a toPostion supplied (likely won't be, dunno if I'll do this) + if(toPosition == null){ + // Get the new position of item based on new boardElement + toPosition = getCurrentPositionAndLength(elementTo, playerTo)[0]+1 + //console.log(toPosition); + } + //console.log('itemKey: '+itemKey+' fromPosition: '+fromPosition+' elementFrom: '+elementFrom+' toPosition: '+toPosition+' playerFrom: '+playerFrom+' playerTo: '+playerTo); + listPosition[itemKey] = toPosition; + + // Move from elementFrom to elementTo + //console.log('elementTo: '+elementTo); + //console.log(boardElement[itemKey]); + boardElement[itemKey] = elementTo; + //console.log(itemKey); + //console.log(boardElement[itemKey]); + + // Move down(0) the positions of elementFrom, from fromPosition for player + this.moveElementPositions(0, elementFrom, fromPosition, playerFrom); + this.drawBoard(); + return 1; // Got a loop that calls a loop, and checks the new values atm, so this keeps counting down + + } + } + } + } + } + moveElementPositions(direction, elementFrom, fromPosition, playerFrom){ + + // Move the positions directionally 1 for elementFrom from fromPosition + //console.log(listPosition); + //console.log('Direction: '+direction+' elementFrom: '+elementFrom+' fromPosition: '+fromPosition+' player: '+playerId); + + // Loop the elementFrom, and move positions for anything after + // item taken from position 34, 35..60 need to be moved down to 34..59 + // For each item + for(let itemKey = 0; itemKey < item.length; itemKey++){ + // If boardElement is elementFrom + if(itemKey in boardElement && boardElement[itemKey] == elementFrom){ + // And from the playerFrom (id) + if(itemKey in player && player[itemKey] == playerFrom){ + //console.log(elementFrom); + //console.log(boardElement[itemKey]); + //console.log(listPosition[itemKey]); + //console.log(itemKey); + if(listPosition[itemKey] > fromPosition){ + //console.log('position: '+listPosition[itemKey]+' fromPosition: '+fromPosition); + // Move items up, i.e. added to top of deck + if(direction){ + listPosition[itemKey]++; + } + // Move items down, i.e. taken from top of deck + listPosition[itemKey]--; + } + + } + } + } + //console.log(listPosition); + + } // Draw a card, traditional TCG drawACard(cardsToDraw = 1){ + + for(let draw = 0; draw < cardsToDraw; draw++){ + // Move from player0, position 0 (top) of deck, to hand + this.addFromBoardElement(0, 0, 'deck', 'hand', null, null); + } + + if(false){ // For loop so that animations will play each time (when they exist) for(let draw = 0; draw < cardsToDraw; draw++){ if(playerHand.length >= maxHandSize){ @@ -470,8 +562,16 @@ class Board{ playerHand.push(cardDrawn); this.drawBoard(); } + } } + drawACardOpponent(cardsToDraw = 1){ + for(let draw = 0; draw < cardsToDraw; draw++){ + // Move from player0, position 0 (top) of deck, to hand + this.addFromBoardElement(1, 0, 'deck', 'hand', null, null); + } + + if(false){ for(let draw = 0; draw < cardsToDraw; draw++){ if(opponentHand.length >= maxHandSize){ alert('Hand full '+opponentHand.length+'/'+maxHandSize); @@ -486,6 +586,7 @@ class Board{ opponentHand.push(cardDrawn); this.drawBoard(); } + } } @@ -832,13 +933,15 @@ let board = new Board; board.playCardToBoardFromDeckOpponent(); board.playCardToBoardFromDeckOpponent(); -board.drawBoard(); +//board.drawBoard(); board.playShield(4); board.playShieldOpponent(4); +board.drawBoard(true); board.drawACard(3); + canvas.addEventListener('contextmenu', function(event) { event.preventDefault(); @@ -1154,16 +1257,35 @@ function calculateItemSizePosition(itemKey){ let itemListPositionNext = itemListPositionLength[0]; let itemListLength = itemListPositionLength[1]; - // TODO:Padding probably will differ between elements let cardPadding = 10; + let positionX = 0; + let positionY = 0; + let width = 0; + let height = 0; + let i = listPosition[itemKey]; - //console.log('cardName: '+cardData[itemKey].name+', i/listPosition: '+i+', listPosition Length: '+itemListLength); + console.log('cardName: '+cardData[itemKey].name+' listPosition/i: '+i); - // TODO:X/Y W/H 100% differs based on the element - let positionX = canvas.width/2 - (cardWidth * (itemListLength - i) - (cardPadding * i)); - let positionY = cardHeight + 30; - let width = cardWidth; - let height = cardHeight; + if(itemPlayer == 1 && itemElement == 'board'){ + positionX = canvas.width/2 - (cardWidth * (itemListLength - i) - (cardPadding * i)); + positionY = cardHeight + 30; + width = cardWidth; + height = cardHeight; + } + if(itemPlayer == 1 && itemElement == 'hand'){ + positionX = canvas.width/2 - (cardWidth * (itemListLength - (i+1)) - (cardPadding * (i+1))); + positionY = 20; + width = cardWidth; + height = cardHeight; + } + if(itemPlayer == 0 && itemElement == 'hand'){ + positionX = canvas.width/2 - (cardWidth * (itemListLength - (i+1)) - (cardPadding * (i+1))); + positionY = canvas.height-cardWidth*1.5-20; + width = cardWidth; + height = cardHeight; + } + + //console.log('cardName: '+cardData[itemKey].name+', i/listPosition: '+i+', listPosition Length: '+itemListLength); // Set the size/position of the item size[itemKey] = [width, height]; From 3c1309a63adcc0e6aba4d37b3dc063536b79a91b Mon Sep 17 00:00:00 2001 From: Nathan Date: Sat, 12 Oct 2024 11:03:09 +0100 Subject: [PATCH 08/41] Add max hand size check ECS --- public/board.js | 52 +++++++++++++++---------------------------------- 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/public/board.js b/public/board.js index 0a9164d..df3d084 100644 --- a/public/board.js +++ b/public/board.js @@ -469,6 +469,8 @@ class Board{ // Move itemKey fromPosition in elementFrom to toPosition in elementTo // Can also switch item between players + + // Loop all items, get the item with boardElement elementFrom and player playerFrom for(let itemKey = 0; itemKey < item.length; itemKey++){ // Get the item from the element if(itemKey in boardElement && boardElement[itemKey] == elementFrom){ @@ -539,53 +541,31 @@ class Board{ } // Draw a card, traditional TCG drawACard(cardsToDraw = 1){ - - for(let draw = 0; draw < cardsToDraw; draw++){ - // Move from player0, position 0 (top) of deck, to hand - this.addFromBoardElement(0, 0, 'deck', 'hand', null, null); - } - - if(false){ - // For loop so that animations will play each time (when they exist) for(let draw = 0; draw < cardsToDraw; draw++){ - if(playerHand.length >= maxHandSize){ - alert('Hand full '+playerHand.length+'/'+maxHandSize); + // Check there's space in hand + // TODO: Normalise this for all element/player combos + let elementLength = getCurrentPositionAndLength('hand', 0)[1]; + if(elementLength >= maxHandSize){ + alert('Hand full '+elementLength+'/'+maxHandSize); return 0; } - - // Random card from deck, remove from deck, add to hand - let cardToDraw = Math.floor(Math.random() * deckCount); - let cardDrawn = playerDeck[cardToDraw]; - // Remove from deck - playerDeck.splice(cardToDraw, 1); - // Add to hand - playerHand.push(cardDrawn); - this.drawBoard(); - } + // Move from player0, position 0 (top) of deck, to hand + this.addFromBoardElement(0, 0, 'deck', 'hand', null, null); } } drawACardOpponent(cardsToDraw = 1){ for(let draw = 0; draw < cardsToDraw; draw++){ - // Move from player0, position 0 (top) of deck, to hand - this.addFromBoardElement(1, 0, 'deck', 'hand', null, null); - } + // Move from player1, position 0 (top) of deck, to hand - if(false){ - for(let draw = 0; draw < cardsToDraw; draw++){ - if(opponentHand.length >= maxHandSize){ - alert('Hand full '+opponentHand.length+'/'+maxHandSize); + // Check there's space in hand + // TODO: Normalise this for all element/player combos + let elementLength = getCurrentPositionAndLength('hand', 1)[1]; + if(elementLength >= maxHandSize){ + alert('Hand full '+elementLength+'/'+maxHandSize); return 0; } - // Random card from deck, remove from deck, add to hand - let cardToDraw = Math.floor(Math.random() * deckCountOpponent); - let cardDrawn = opponentDeck[cardToDraw]; - // Remove from deck - opponentDeck.splice(cardToDraw, 1); - // Add to hand - opponentHand.push(cardDrawn); - this.drawBoard(); - } + this.addFromBoardElement(1, 0, 'deck', 'hand', null, null); } } From 5d059aedebd449de113e3eb1c2fb3a38d8dfe4d6 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sat, 12 Oct 2024 11:10:21 +0100 Subject: [PATCH 09/41] Remove old drawHand methods --- public/board.js | 47 ----------------------------------------------- 1 file changed, 47 deletions(-) diff --git a/public/board.js b/public/board.js index df3d084..939dc75 100644 --- a/public/board.js +++ b/public/board.js @@ -89,9 +89,6 @@ class Board{ this.drawShield(); this.drawShieldOpponent(); - this.drawHand(); - this.drawOpponentHand(); - this.drawMana(); this.drawPlayerNames('Nathan', 'Evil Nathan'); @@ -417,50 +414,6 @@ class Board{ ctx.fillText(opponentDeck.length, cardWidth*1.5 + (ctx.measureText(opponentDeck.length).width) + 10, cardHeight*1.9); } - // Naming's getting awkward here... - // Draw the cards in hand - drawHand(){ - // Player Hand/Cards in Hand - for (let i = 0; i < playerHand.length; i++) { - - let name = 'cardInHand_'+(i+1); - - let cardPadding = 10; - let fill = '#'+i+i+'FF00'; - - // TODO: fix positionX, actually have some maffs - let positionX = canvas.width/2 - (cardWidth * (playerHand.length - (i+1)) - (cardPadding * (i+1))); - let positionY = canvas.height-cardWidth*1.5-20; - let width = cardWidth; - let height = cardHeight; - - this.drawCard(playerHand, i, name, positionX, positionY, width, height, fill); - } - - } - - drawOpponentHand(){ - // Opponents Hand/Cards in Hand - for (let i = 0; i < opponentHand.length; i++) { - - let name = 'cardInOpponentsHand_'+(i+1); - - let cardPadding = 10; - let fill = '#'+i+i+'DD00'; - - // TODO: fix positionX, actually have some maffs - let positionX = canvas.width/2 - (cardWidth * (opponentHand.length - (i+1)) - (cardPadding * (i+1))); - let positionY = 20; - let width = cardWidth; - let height = cardHeight; - - this.drawCard(opponentHand, i, name, positionX, positionY, width, height, fill); - } - - } - - drawCards(){} - addFromBoardElement(playerFrom, fromPosition, elementFrom, elementTo, toPosition=null, playerTo=null){ if(playerTo == null){ playerTo = playerFrom; From 0c5b52adeda18594b5d87158c16f1b7fbbd16010 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sat, 12 Oct 2024 12:58:52 +0100 Subject: [PATCH 10/41] Move drawDecks to one method, Fix deck counter --- public/board.js | 145 +++++++++++++++++++++++++++++++----------------- 1 file changed, 93 insertions(+), 52 deletions(-) diff --git a/public/board.js b/public/board.js index 939dc75..ed5d5dc 100644 --- a/public/board.js +++ b/public/board.js @@ -83,8 +83,7 @@ class Board{ this.drawCardsOnBoard(); this.drawCardsOnBoardOpponent(); - this.drawDeck(); - this.drawDeckOpponent(); + this.drawDecks(); this.drawShield(); this.drawShieldOpponent(); @@ -360,58 +359,100 @@ class Board{ ctx.font = "10pt Arial"; } - drawDeck(){ - // Deck - clickableItems['deckSprite'] = new Shape({ - name: 'deck', - x: canvas.width-cardWidth*1.5-40, - y: canvas.height-cardHeight*1.5-60, - width: cardWidth*1.5, - height: cardHeight*1.5, - fillStyle: "#0000FF" - }); - //ctx.fillRect(canvas.width-cardWidth/2-60, canvas.height/2-cardHeight/4, cardWidth/2, cardHeight/2); - clickableItems['deckSprite'].draw(); - let deckCounterSprite = new Shape({ - shape: 'circle', - name: 'deckCounter', - x: canvas.width-cardWidth*.6, - y: canvas.height-cardHeight*.6, - width: cardWidth*.375, - height: cardHeight*.375, - fillStyle: "#FFF" - }); - deckCounterSprite.draw(); + drawDecks(){ + // Draw all decks belonging to players (currently 2, could be 3-5 in future, for PvE raids) + // TODO: Probably add this as an item of boardElement 'realDeck', as 'deck' is cards in deck + // actually, maybe change current 'deck' to 'inDeck', reads better + let name = null; + let countername = null; + let x = null; + let counterx = null; + let y = null; + let countery = null; + let width = null; + let counterwidth = null; + let height = null; + let counterheight = null; + let fill = null; + let counterfill = '#FFF'; + let textx = null; + let texty = null; + let deckLength = 0; + + for(let playerId = 0; playerId < players; playerId++){ + if(playerId == 0){ + // Deck + name= 'deck'; + x= canvas.width-cardWidth*1.5-40; + y= canvas.height-cardHeight*1.5-60; + width= cardWidth*1.5; + height= cardHeight*1.5; + fill= "#0000FF"; + + countername= 'deckCounter'; + counterx= canvas.width-cardWidth*.6; + countery= canvas.height-cardHeight*.6; + counterwidth= cardWidth*.375; + counterheight= cardHeight*.375; + + // TODO: Center in the circle + deckLength = getCurrentPositionAndLength('deck', 0)[1]; + textx = canvas.width-cardWidth*.6 - (ctx.measureText(deckLength).width) + 7; + texty = canvas.height-cardHeight*.6 + 5; + } + if(playerId == 1){ + // Opponent's Deck + name= 'deckOpponent'; + x= 40; + y= 60; + width= cardWidth*1.5; + height= cardHeight*1.5; + fill= "#FF0000"; + + countername= 'deckCounterOpponent'; + counterx= cardWidth*1.5+(cardWidth*.375); + countery= cardHeight*1.5+(cardHeight*.375); + counterwidth= cardWidth*.375; + counterheight= cardHeight*.375; + counterfill= "#FFF"; + + deckLength = getCurrentPositionAndLength('deck', 1)[1]; + textx=cardWidth*1.5 + (ctx.measureText(deckLength).width) + 10; + texty=cardHeight*1.9; - // TODO: Center in the circle - ctx.fillStyle = '#000'; - ctx.fillText(playerDeck.length, canvas.width-cardWidth*.6 - (ctx.measureText(playerDeck.length).width) + 7, canvas.height-cardHeight*.6 + 5); - } - drawDeckOpponent(){ - // Opponent's Deck - clickableItems['deckOpponentSprite'] = new Shape({ - name: 'deckOpponent', - x: 40, - y: 60, - width: cardWidth*1.5, - height: cardHeight*1.5, - fillStyle: "#FF0000" - }); - clickableItems['deckOpponentSprite'].draw(); - let deckCounterOpponentSprite = new Shape({ - shape: 'circle', - name: 'deckCounterOpponent', - x: cardWidth*1.5+(cardWidth*.375), - y: cardHeight*1.5+(cardHeight*.375), - width: cardWidth*.375, - height: cardHeight*.375, - fillStyle: "#FFF" - }); - deckCounterOpponentSprite.draw(); + } + + // Actually draw the decks base on the size/position, etc. + clickableItems[name+'Sprite'] = new Shape({ + name: name, + x: x, + y: y, + width: width, + height: height, + fillStyle: fill + }); + //ctx.fillRect(canvas.width-cardWidth/2-60, canvas.height/2-cardHeight/4, cardWidth/2, cardHeight/2); + clickableItems[name+'Sprite'].draw(); + + // Draw circle for deck count to sit in + let deckCounterSprite = new Shape({ + shape: 'circle', + name: countername, + x: counterx, + y: countery, + width: counterwidth, + height: counterheight, + fillStyle: counterfill + }); + console.log(deckCounterSprite); + deckCounterSprite.draw(); + + // Draw deck count text + // TODO: Center in the circle + ctx.fillStyle = '#000'; + ctx.fillText(deckLength, textx, texty); + } - ctx.fillStyle = '#000'; - // TODO: Center in the circle - ctx.fillText(opponentDeck.length, cardWidth*1.5 + (ctx.measureText(opponentDeck.length).width) + 10, cardHeight*1.9); } addFromBoardElement(playerFrom, fromPosition, elementFrom, elementTo, toPosition=null, playerTo=null){ From 10b02f5f383048bda4205a4a53724d43afe7e22b Mon Sep 17 00:00:00 2001 From: Nathan Date: Sat, 12 Oct 2024 13:19:17 +0100 Subject: [PATCH 11/41] Fix onclick trigger events per boardElement --- public/board.js | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/public/board.js b/public/board.js index ed5d5dc..f36de0b 100644 --- a/public/board.js +++ b/public/board.js @@ -927,6 +927,34 @@ canvas.addEventListener('contextmenu', function(event) { var x = event.pageX - canvasLeft, y = event.pageY - canvasTop; + for(let itemKey = 0; itemKey < item.length; itemKey++){ + + if(elements[itemKey] == 'deck'){ + continue; + } + + // Check the item has a size and position + if(itemKey in size && itemKey in position){ + // Compare the event XY position to the item + if(clickableCheck(x,y,false,itemKey)){ + // Only want to happen once (for now) + // Maybe in future add to hand would trigger another event if there's an effect? + + // Check the location of element + switch(boardElement[itemKey]){ + // Check item location, and trigger events based on it + case 'board': + // Untap + cardStatus[itemKey] = null; + case 'hand': + // Can be played as mana (right click for now) + } + } + } + + board.drawBoard(); + } + // # PLAYER HAND playerHand.forEach(function(card, index){ @@ -973,12 +1001,25 @@ canvas.addEventListener('click', function(event) { if(itemKey in size && itemKey in position){ // Compare the event XY position to the item if(clickableCheck(x,y,false,itemKey)){ - cardStatus[itemKey] = 'tapped'; + // Only want to happen once (for now) + // Maybe in future add to hand would trigger another event if there's an effect? + + // Check the location of element + switch(boardElement[itemKey]){ + // Check item location, and trigger events based on it + case 'board': + // Can attack + // board.startAttack(index); + // Get tapped + cardStatus[itemKey] = 'tapped'; + case 'hand': + // Can be played + //board.playCardToBoard(index); + } } } board.drawBoard(); - } From e7ea3b2b88e09f27ff6ff5e5ffc33c0ab6895765 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sat, 12 Oct 2024 13:22:26 +0100 Subject: [PATCH 12/41] Remove drawOnBoardOpponent as rewritten --- public/board.js | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/public/board.js b/public/board.js index f36de0b..8f7eccd 100644 --- a/public/board.js +++ b/public/board.js @@ -81,7 +81,6 @@ class Board{ ctx.fillText(name, 0, 10); this.drawCardsOnBoard(); - this.drawCardsOnBoardOpponent(); this.drawDecks(); @@ -587,27 +586,6 @@ class Board{ } } - drawCardsOnBoardOpponent(){ - // OLD, being rewritten - if(true){ - for (let i = 0; i < opponentBoard.length; i++) { - - let name = 'cardOnBoardOpponent_'+(i+1); - - let cardPadding = 10; - let fill = '#'+i+i+'AA00'; - - // TODO: fix positionX, actually have some maffs - let positionX = canvas.width/2 - (cardWidth * (opponentBoard.length - (i+1)) - (cardPadding * (i+1))); - let positionY = cardHeight + 30; - let width = cardWidth; - let height = cardHeight; - - this.drawCard(opponentBoard, i, name, positionX, positionY, width, height, fill); - } - } - } - // Currently only functionality in hand playCardToBoard(index){ // Get the card data From c89640e33a3b6d2f97485201718d25409817aaa1 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sat, 12 Oct 2024 14:05:19 +0100 Subject: [PATCH 13/41] Play card from hand to board --- public/board.js | 73 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/public/board.js b/public/board.js index 8f7eccd..9046a1d 100644 --- a/public/board.js +++ b/public/board.js @@ -148,12 +148,12 @@ class Board{ // Draw Elements // Loop each item left, and draw if element is currently looped. board,mana,etc. if(itemKey in boardElement && boardElement[itemKey] == element){ - if(boardElement[itemKey] == 'hand' && player[itemKey] == 0){ - console.log('PLAYER HAND'); + if(boardElement[itemKey] == 'board' && player[itemKey] == 0){ + console.log('PLAYER BOARD'); } // Get the player the item belongs to let itemPlayer = player[itemKey]; - console.log('Element: '+element+', Player: '+itemPlayer); + //console.log('Element: '+element+', Player: '+itemPlayer); calculateItemSizePosition(itemKey); @@ -443,7 +443,6 @@ class Board{ height: counterheight, fillStyle: counterfill }); - console.log(deckCounterSprite); deckCounterSprite.draw(); // Draw deck count text @@ -478,7 +477,7 @@ class Board{ toPosition = getCurrentPositionAndLength(elementTo, playerTo)[0]+1 //console.log(toPosition); } - //console.log('itemKey: '+itemKey+' fromPosition: '+fromPosition+' elementFrom: '+elementFrom+' toPosition: '+toPosition+' playerFrom: '+playerFrom+' playerTo: '+playerTo); + console.log('itemKey: '+itemKey+' fromPosition: '+fromPosition+' elementFrom: '+elementFrom+' elementTo: '+elementTo+' toPosition: '+toPosition+' playerFrom: '+playerFrom+' playerTo: '+playerTo); listPosition[itemKey] = toPosition; // Move from elementFrom to elementTo @@ -489,7 +488,11 @@ class Board{ //console.log(boardElement[itemKey]); // Move down(0) the positions of elementFrom, from fromPosition for player + console.log(JSON.stringify(boardElement)); + console.log(JSON.stringify(listPosition)); this.moveElementPositions(0, elementFrom, fromPosition, playerFrom); + console.log(JSON.stringify(boardElement)); + console.log(JSON.stringify(listPosition)); this.drawBoard(); return 1; // Got a loop that calls a loop, and checks the new values atm, so this keeps counting down @@ -587,18 +590,36 @@ class Board{ } // Currently only functionality in hand - playCardToBoard(index){ + playCardToBoard(positionInHand, cardsToPlay = 1){ + + console.log(positionInHand); + // Loop probably not needed, but may be for eg. 'play X cards from top of deck' + for(let play = 0; play < cardsToPlay; play++){ + // Check there's space on board TODO: change to locationTo + // TODO: Normalise this for all element/player combos + let elementLength = getCurrentPositionAndLength('board', 0)[1]; + if(elementLength >= maxHandSize){ + alert('Board full '+elementLength+'/'+maxHandSize); + return 0; + } + // When done remove false && + // TODO: Rewrite for ECS + // Mana cost required and mana tapping + if(false && cardPlayed.cost > playerMana.length){ + alert('Not enough mana'); + return 0; + } + + // Move from player0, position 0 (top) of deck, to hand + this.addFromBoardElement(0, positionInHand, 'hand', 'board', null, null); + } + + + if(false){ // Get the card data let cardPlayed = playerHand[index]; let manaUsed = []; - // Check if there's space on board to play - // TODO: Check this in back-end - if(playerBoard.length >= maxBoardSize){ - alert('No space on board to play card. '+playerBoard.length+'/'+maxBoardSize); - return 0; - } - if(cardPlayed.cost > playerMana.length){ alert('Not enough mana'); return 0; @@ -635,6 +656,7 @@ class Board{ playerHand.splice(index, 1); // Add to board playerBoard.push(cardPlayed); + } this.drawBoard(); } @@ -882,8 +904,8 @@ let board = new Board; //shuffleDeck(1); // TEMP: Play a card on opponents board (from their deck) -board.playCardToBoardFromDeckOpponent(); -board.playCardToBoardFromDeckOpponent(); +//board.playCardToBoardFromDeckOpponent(); +//board.playCardToBoardFromDeckOpponent(); //board.drawBoard(); @@ -891,7 +913,7 @@ board.playShield(4); board.playShieldOpponent(4); board.drawBoard(true); -board.drawACard(3); +//board.drawACard(3); canvas.addEventListener('contextmenu', function(event) { @@ -992,7 +1014,8 @@ canvas.addEventListener('click', function(event) { cardStatus[itemKey] = 'tapped'; case 'hand': // Can be played - //board.playCardToBoard(index); + // Play from item listPosition, 1 card + board.playCardToBoard(listPosition[itemKey], 1); } } } @@ -1039,6 +1062,7 @@ canvas.addEventListener('click', function(event) { } // # PLAYER HAND + if(false){ playerHand.forEach(function(card, index){ let clickable = card.clickable; @@ -1054,6 +1078,7 @@ canvas.addEventListener('click', function(event) { board.drawBoard(); } }); + } // # PLAYER BOARD playerBoard.forEach(function(card, index){ @@ -1107,13 +1132,13 @@ function clickableCheck(x,y,clickable=false,itemKey=false){ // simultaneously. It works, so that's nice if(clickable === false && itemKey !== false){ clickable = {}; - console.log(clickable); - console.log(itemKey); + //console.log(clickable); + //console.log(itemKey); clickable.x = position[itemKey][0]; clickable.y = position[itemKey][1]; clickable.width = size[itemKey][0]; clickable.height = size[itemKey][1]; - console.log(clickable); + //console.log(clickable); } // Debug Stuff @@ -1257,7 +1282,7 @@ function calculateItemSizePosition(itemKey){ let height = 0; let i = listPosition[itemKey]; - console.log('cardName: '+cardData[itemKey].name+' listPosition/i: '+i); + //console.log('cardName: '+cardData[itemKey].name+' listPosition/i: '+i); if(itemPlayer == 1 && itemElement == 'board'){ positionX = canvas.width/2 - (cardWidth * (itemListLength - i) - (cardPadding * i)); @@ -1271,6 +1296,12 @@ function calculateItemSizePosition(itemKey){ width = cardWidth; height = cardHeight; } + if(itemPlayer == 0 && itemElement == 'board'){ + positionX = canvas.width/2 - (cardWidth * (itemListLength - (i+1)) - (cardPadding * (i+1))); + positionY = canvas.height - cardHeight-30-(cardHeight); + width = cardWidth; + height = cardHeight; + } if(itemPlayer == 0 && itemElement == 'hand'){ positionX = canvas.width/2 - (cardWidth * (itemListLength - (i+1)) - (cardPadding * (i+1))); positionY = canvas.height-cardWidth*1.5-20; From 75aea0308b5bfe916f955c8cc948496dd5ae40d8 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sat, 12 Oct 2024 18:39:25 +0100 Subject: [PATCH 14/41] Draw all existing elements ECS-ey --- public/board.js | 287 +++++++++++++++++++----------------------------- 1 file changed, 115 insertions(+), 172 deletions(-) diff --git a/public/board.js b/public/board.js index 9046a1d..542084a 100644 --- a/public/board.js +++ b/public/board.js @@ -84,11 +84,6 @@ class Board{ this.drawDecks(); - this.drawShield(); - this.drawShieldOpponent(); - - this.drawMana(); - this.drawPlayerNames('Nathan', 'Evil Nathan'); this.drawCardsECS(); // Atop most everything atm for testing @@ -590,34 +585,39 @@ class Board{ } // Currently only functionality in hand - playCardToBoard(positionInHand, cardsToPlay = 1){ + playCardToBoard(positionFrom, fromElement, toElement, fromPlayer, toPlayer = null, cardsToPlay = 1){ + + // TODO: if from hand, use mana according to the card cost + mana types + if(toPlayer === null){ + toPlayer = fromPlayer; + } - console.log(positionInHand); // Loop probably not needed, but may be for eg. 'play X cards from top of deck' for(let play = 0; play < cardsToPlay; play++){ // Check there's space on board TODO: change to locationTo // TODO: Normalise this for all element/player combos - let elementLength = getCurrentPositionAndLength('board', 0)[1]; + let elementLength = getCurrentPositionAndLength(toElement, toPlayer)[1]; + // TODO: Compare against the maxSize for the boardElement + // this is fine(ish) for now, as just using hand if(elementLength >= maxHandSize){ alert('Board full '+elementLength+'/'+maxHandSize); return 0; } // When done remove false && // TODO: Rewrite for ECS - // Mana cost required and mana tapping + // Mana cost required and mana tapping for playing a card from hand, etc if(false && cardPlayed.cost > playerMana.length){ alert('Not enough mana'); return 0; } - // Move from player0, position 0 (top) of deck, to hand - this.addFromBoardElement(0, positionInHand, 'hand', 'board', null, null); + // Move from player0, position 0 (top) of deck, to hand, to pos(null/auto) for toPlayer + this.addFromBoardElement(fromPlayer, positionFrom, fromElement, toElement, null, toPlayer); } + // Needs doing for playing cards from hand if(false){ - // Get the card data - let cardPlayed = playerHand[index]; let manaUsed = []; if(cardPlayed.cost > playerMana.length){ @@ -650,43 +650,6 @@ class Board{ playerMana[cardKey].tapped = true; }); - console.log(playerMana); - - // Remove from hand - playerHand.splice(index, 1); - // Add to board - playerBoard.push(cardPlayed); - } - - this.drawBoard(); - } - playCardToBoardFromDeckOpponent(){ - - if(opponentBoard.length >= maxBoardSize){ - alert('No space on board to play card. '+opponentBoard.length+'/'+maxBoardSize); - return 0; - } - - // Loop items for opponent deck. boardElement = deck, and player = 1 - for(let itemKey = 0; itemKey < item.length; itemKey++){ - // Check if item is in deck - // 'key' in 'object' - if(itemKey in boardElement && boardElement[itemKey] == 'deck'){ - // Check if item belongs to opponent - if(itemKey in player && player[itemKey] == 1){ - // Check list position for top of deck - if(listPosition[itemKey] == 0){ - // Set the new position (on board) - listPosition[itemKey] = getCurrentPositionAndLength('board', 1)[0]+1 - // Move from current item to board - boardElement[itemKey] = 'board'; - } - else{ - // Move all other items in deck down in position by 1 to get new 0 - listPosition[itemKey]--; - } - } - } } this.drawBoard(); @@ -771,7 +734,22 @@ class Board{ // Like everything else, need to consolidate into one function that // can work for both players, and even more for 2v2 3v1 combats, etc. - playShield(shieldsToPlay = 4){ + playShield(fromPosition, fromElement, playerId, cardsToPlay = 1){ + for(let shieldNo = 0; shieldNo < cardsToPlay; shieldNo++){ + // Check there's space for shield TODO: change to locationTo + // TODO: Normalise this for all element/player combos + let elementLength = getCurrentPositionAndLength('shield', playerId)[1]; + if(elementLength >= maxShield){ + alert('Shield full '+elementLength+'/'+maxShield); + // Kill loop if there's too many shiled already, no need re-notifying + return 0; + } + + // Move from player, position 0 (top) of deck, to hand (next available position) + this.addFromBoardElement(playerId, fromPosition, fromElement, 'shield', null, null); + } + + if(false){ for(let shieldNo = 0; shieldNo < shieldsToPlay; shieldNo++){ if(playerShield.length >= maxShield){ alert('Shield zone full '+playerShield.length+'/'+maxShield); @@ -787,73 +765,16 @@ class Board{ playerShield.push(cardDrawn); this.drawBoard(); } - } - playShieldOpponent(shieldsToPlay = 4){ - for(let shieldNo = 0; shieldNo < shieldsToPlay; shieldNo++){ - if(opponentShield.length >= maxShield){ - alert('Shield zone full '+opponentShield.length+'/'+maxShield); - return 0; - } - - // Random card from deck, remove from deck, add to hand - let cardToDraw = Math.floor(Math.random() * deckCount); - let cardDrawn = opponentDeck[cardToDraw]; - // Remove from deck - opponentDeck.splice(cardToDraw, 1); - // Add to shield zone - opponentShield.push(cardDrawn); - this.drawBoard(); - } - } - drawShield(){ - for (let i = 0; i < playerShield.length; i++) { - - let name = 'playerShield_'+(i+1); - - let shieldMargin = 10; - let fromX = 60; - let fromY = 300; - let fill = '#'+i+i+'0000'; - let cWidth = cardWidth*.8; - let cHeight = cardHeight*.8; - let split = 0; - if(i>=2){ split = 1; } - - // i%2 0 = 0, 1 = 1, 2 = 0, 3 = 1 to prevent margin from X/Y axis, and just between cards - let positionX = (fromX+((i%2)*shieldMargin)) +(i%2*cWidth); - let positionY = canvas.height-fromY+(split*cHeight+(shieldMargin*split)); - let width = cWidth; - let height = cHeight; - - this.drawCard(playerShield, i, name, positionX, positionY, width, height, fill); - } - } - drawShieldOpponent(){ - for (let i = 0; i < opponentShield.length; i++) { - - let name = 'opponentShield_'+(i+1); - - let shieldMargin = 10; - let fromX = canvas.width-60; - let fromY = 300; - let fill = '#'+i+i+'0000'; - let cWidth = cardWidth*.8; - let cHeight = cardHeight*.8; - let split = 0; - if(i>=2){ split = 1; } - - // i%2 0 = 0, 1 = 1, 2 = 0, 3 = 1 to prevent margin from X/Y axis, and just between cards - let positionX = (fromX+((i%2)*shieldMargin))+(i%2*cWidth)-(cWidth*2); - let positionY = fromY+(split*cHeight+(shieldMargin*split))-(cHeight*2 + shieldMargin); - let width = cWidth; - let height = cHeight; - //console.log('i: '+i+' X: '+positionX+' Y: '+positionY); - - this.drawCard(opponentShield, i, name, positionX, positionY, width, height, fill); } } - playMana(index, fromDeck = 0){ + playMana(fromPosition, fromElement, cardsToPlay = 1){ + // Move from player0, fromPosition of hand (for now), to mana + // TODO: FOR ALL addFromBoardElements, if 'fromPosition' not passed get the + // fromPosition and boardElementFrom from the itemId (will need to change to pass this) + this.addFromBoardElement(0, fromPosition, fromElement, 'mana', null, null); + + if(false){ let manaCard = null; if(fromDeck){ let cardToDraw = Math.floor(Math.random() * deckCount); @@ -868,27 +789,6 @@ class Board{ playerMana.push(manaCard); this.drawBoard(); - } - drawMana(){ - for (let i = 0; i < playerMana.length; i++) { - - let name = 'playerMana_'+(i+1); - - let manaMargin = 10; - let fromX = 60; - let fromY = 60; - let fill = '#BBB'; - let cWidth = cardWidth*.5; - let cHeight = cardHeight*.5; - let split = 0; - - // i%2 0 = 0, 1 = 1, 2 = 0, 3 = 1 to prevent margin from X/Y axis, and just between cards - let positionX = (fromX+manaMargin)+(i*cWidth-manaMargin); - let positionY = canvas.height-fromY; - let width = cWidth; - let height = cHeight; - - this.drawCard(playerMana, i, name, positionX, positionY, width, height, fill); } } } @@ -903,14 +803,14 @@ let board = new Board; //shuffleDeck(0); //shuffleDeck(1); -// TEMP: Play a card on opponents board (from their deck) -//board.playCardToBoardFromDeckOpponent(); -//board.playCardToBoardFromDeckOpponent(); - //board.drawBoard(); -board.playShield(4); -board.playShieldOpponent(4); +// Play 4 shield from position 0 (top) of deck, for player 0 (you) +// TODO:May want to change this to play from opponents deck, or hand, etc. for future +// That will likely be a while though I assume? +board.playShield(0, 'deck', 0, 4); +board.playShield(0, 'deck', 1, 4); +//board.playShieldOpponent(4); board.drawBoard(true); //board.drawACard(3); @@ -940,19 +840,24 @@ canvas.addEventListener('contextmenu', function(event) { // Only want to happen once (for now) // Maybe in future add to hand would trigger another event if there's an effect? + console.log(boardElement[itemKey]); // Check the location of element switch(boardElement[itemKey]){ // Check item location, and trigger events based on it case 'board': // Untap cardStatus[itemKey] = null; + board.drawBoard(); + break; case 'hand': // Can be played as mana (right click for now) + // Play item from boardElement hand. To boardElement mana (explanitory) + board.playMana(listPosition[itemKey], 'hand'); + board.drawBoard(); + break; } } } - - board.drawBoard(); } // # PLAYER HAND @@ -1004,6 +909,10 @@ canvas.addEventListener('click', function(event) { // Only want to happen once (for now) // Maybe in future add to hand would trigger another event if there's an effect? + // Get the playerId of who the item belongs to + // TODO: Some other playerId may be needed to for 'mind control' cards + let playerId = player[itemKey]; + // Check the location of element switch(boardElement[itemKey]){ // Check item location, and trigger events based on it @@ -1012,15 +921,18 @@ canvas.addEventListener('click', function(event) { // board.startAttack(index); // Get tapped cardStatus[itemKey] = 'tapped'; + board.drawBoard(); + break; case 'hand': // Can be played - // Play from item listPosition, 1 card - board.playCardToBoard(listPosition[itemKey], 1); + // Play 1 item in listPosition, from hand, to board (case from leftmost, etc) + // from playerId, to playerId + board.playCardToBoard(listPosition[itemKey], 'hand', 'board', playerId, playerId, 1); + board.drawBoard(); + break; } } } - - board.drawBoard(); } @@ -1061,25 +973,6 @@ canvas.addEventListener('click', function(event) { board.drawACardOpponent(); } - // # PLAYER HAND - if(false){ - playerHand.forEach(function(card, index){ - - let clickable = card.clickable; - - if(clickableCheck(x,y,clickable) && !specialEvent){ - - board.playCardToBoard(index); - - // This would actually fire off a socketIO doodad, that would then return - // data, and redraw. But for now (UI test) - - // Add to board - board.drawBoard(); - } - }); - } - // # PLAYER BOARD playerBoard.forEach(function(card, index){ let clickable = card.clickable; @@ -1267,6 +1160,9 @@ function calculateItemSizePosition(itemKey){ // Calc position and size of the item // Used for drawing and interacting + + // TODO: Make better calculations and positions for here (also rescaling in future) + // TODO: Maybe instead of checking each player/element combo in if, do some fancy loop? let itemPlayer = player[itemKey]; let itemElement = boardElement[itemKey]; @@ -1275,7 +1171,7 @@ function calculateItemSizePosition(itemKey){ let itemListPositionNext = itemListPositionLength[0]; let itemListLength = itemListPositionLength[1]; - let cardPadding = 10; + let cardMargin = 10; let positionX = 0; let positionY = 0; let width = 0; @@ -1285,29 +1181,76 @@ function calculateItemSizePosition(itemKey){ //console.log('cardName: '+cardData[itemKey].name+' listPosition/i: '+i); if(itemPlayer == 1 && itemElement == 'board'){ - positionX = canvas.width/2 - (cardWidth * (itemListLength - i) - (cardPadding * i)); + positionX = canvas.width/2 - (cardWidth * (itemListLength - i) - (cardMargin * i)); positionY = cardHeight + 30; width = cardWidth; height = cardHeight; } if(itemPlayer == 1 && itemElement == 'hand'){ - positionX = canvas.width/2 - (cardWidth * (itemListLength - (i+1)) - (cardPadding * (i+1))); + positionX = canvas.width/2 - (cardWidth * (itemListLength - (i+1)) - (cardMargin * (i+1))); positionY = 20; width = cardWidth; height = cardHeight; } + if(itemPlayer == 1 && itemElement == 'mana'){ + + } + if(itemPlayer == 1 && itemElement == 'shield'){ + let fromX = canvas.width-60; + let fromY = 300; + let cWidth = cardWidth*.8; + let cHeight = cardHeight*.8; + let split = 0; + // i-1 here as it's based on 0 being start, like array. + // If there's 2 in a row, split onto next row + // TODO: Not sure if I want to start elements at 1 (for clienty) or 0 (for programmy) + if(i-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 + positionX = (fromX+((i%2)*cardMargin))+(i%2*cWidth)-(cWidth*2); + positionY = fromY+(split*cHeight+(cardMargin*split))-(cHeight*2 + cardMargin); + width = cWidth; + height = cHeight; + + } if(itemPlayer == 0 && itemElement == 'board'){ - positionX = canvas.width/2 - (cardWidth * (itemListLength - (i+1)) - (cardPadding * (i+1))); + positionX = canvas.width/2 - (cardWidth * (itemListLength - (i+1)) - (cardMargin * (i+1))); positionY = canvas.height - cardHeight-30-(cardHeight); width = cardWidth; height = cardHeight; } if(itemPlayer == 0 && itemElement == 'hand'){ - positionX = canvas.width/2 - (cardWidth * (itemListLength - (i+1)) - (cardPadding * (i+1))); + positionX = canvas.width/2 - (cardWidth * (itemListLength - (i+1)) - (cardMargin * (i+1))); positionY = canvas.height-cardWidth*1.5-20; width = cardWidth; height = cardHeight; } + if(itemPlayer == 0 && itemElement == 'mana'){ + let fromX = 60; + let fromY = 60; + let cWidth = cardWidth*.5; + let cHeight = cardHeight*.5; + + positionX = (fromX+cardMargin)+(i*cWidth-cardMargin); + positionY = canvas.height-fromY; + width = cWidth; + height = cHeight; + } + if(itemPlayer == 0 && itemElement == 'shield'){ + let fromX = 60; + let fromY = 300; + let cWidth = cardWidth*.8; + let cHeight = cardHeight*.8; + let split = 0; + // 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(i-1>=2){ split = 1; } + + positionX = (fromX+((i%2)*cardMargin)) +(i%2*cWidth); + positionY = canvas.height-fromY+(split*cHeight+(cardMargin*split)); + width = cWidth; + height = cHeight; + } //console.log('cardName: '+cardData[itemKey].name+', i/listPosition: '+i+', listPosition Length: '+itemListLength); From 6f3ae033ace2f047842923d0209ef5fbd80d3f3d Mon Sep 17 00:00:00 2001 From: Nathan Date: Sat, 12 Oct 2024 23:25:04 +0100 Subject: [PATCH 15/41] Rewrite attack logic to ECS --- public/board.js | 331 +++++++++++++++++++++++++++--------------------- 1 file changed, 184 insertions(+), 147 deletions(-) diff --git a/public/board.js b/public/board.js index 542084a..48beb1f 100644 --- a/public/board.js +++ b/public/board.js @@ -30,9 +30,10 @@ let cardData = {}; let position = {}; let size = {}; //let shape = {}; -let cardStatus = {}; // tapped, attacking, inspected, untargettable +let cardStatus = {}; // tapped, attacking, inspected, untargettable (TODO:maybe used this instead of inEvent later) let player = {}; let listPosition = {}; +let inEvent = null; let playerHand = []; let opponentHand = []; @@ -58,7 +59,6 @@ const maxShield = 4; let inspectCard = null; let attackingCard = null; -let gameWin = 0; // Gonna need lots of refactoring, and sorting class Board{ @@ -88,13 +88,23 @@ class Board{ this.drawCardsECS(); // Atop most everything atm for testing - if(gameWin){ + if(this.checkGameWin == true){ this.drawWin(); } this.drawInspectedCard(); } + checkGameWin(){ + // TODO: Change logic to ECSey, and move into main loop (for other win-cons besides direct attack) + if(false){ + if(opponentShield.length <= 0){ + return true; + } + } + return false; + } + drawWin(){ var winBoard = new Shape({ name: name, @@ -165,6 +175,7 @@ class Board{ // Check status, and change border colour for display (for tapped atm) let border = null; if(cardStatus[itemKey] == 'tapped'){border = '#E0BC00';} + if(cardStatus[itemKey] == 'attacking'){border = '#C92D22';} // Set the card 'cardboard' colour based on the card colour type let colourId = cardData[itemKey].colour; @@ -472,7 +483,7 @@ class Board{ toPosition = getCurrentPositionAndLength(elementTo, playerTo)[0]+1 //console.log(toPosition); } - console.log('itemKey: '+itemKey+' fromPosition: '+fromPosition+' elementFrom: '+elementFrom+' elementTo: '+elementTo+' toPosition: '+toPosition+' playerFrom: '+playerFrom+' playerTo: '+playerTo); + //console.log('itemKey: '+itemKey+' fromPosition: '+fromPosition+' elementFrom: '+elementFrom+' elementTo: '+elementTo+' toPosition: '+toPosition+' playerFrom: '+playerFrom+' playerTo: '+playerTo); listPosition[itemKey] = toPosition; // Move from elementFrom to elementTo @@ -483,11 +494,11 @@ class Board{ //console.log(boardElement[itemKey]); // Move down(0) the positions of elementFrom, from fromPosition for player - console.log(JSON.stringify(boardElement)); - console.log(JSON.stringify(listPosition)); + //console.log(JSON.stringify(boardElement)); + //console.log(JSON.stringify(listPosition)); this.moveElementPositions(0, elementFrom, fromPosition, playerFrom); - console.log(JSON.stringify(boardElement)); - console.log(JSON.stringify(listPosition)); + //console.log(JSON.stringify(boardElement)); + //console.log(JSON.stringify(listPosition)); this.drawBoard(); return 1; // Got a loop that calls a loop, and checks the new values atm, so this keeps counting down @@ -675,60 +686,95 @@ class Board{ // Selects the card that will be attacking // Stop other actions besides selecting opponent/opponent unit // Can cancel, will do later - startAttack(index){ + // Rename to attack intent? + startAttack(itemAttacking){ // Can probably combine attacking/inspect, and set another array element to 'attacking', 'inspecting', etc. - attackingCard = [playerBoard[index], index]; + + // Do error/legal checks here + if(cardStatus[itemAttacking] == 'tapped'){ + alert('Cannot attack, as tapped'); + return false; + } + // Set event + inEvent = ['attack', itemAttacking]; + // Set the status of card to attacking for drawing. + // In future this may be what's used for check (or other in case you can attack with multiple units at once) + cardStatus[itemAttacking] = 'attacking'; + this.drawBoard(); } // Do the attack - makeAttack(index, array = null, name = null){ - if(array == null){ array = opponentBoard; name = 'opponentBoard' } - console.log(name); - // If card attacked - // Compare attackingCard and defendingCard - - let defendingCard = array[index]; - - // If hitting shield, don't calc combat damage - if(name == 'opponentShield'){ - // This should tap the card first, then after all shields - // are tapped, THEN attacking destroys them - if(array[index].tapped){ - // Untap - array[index].tapped = false; - // Add to hand - opponentHand.push(array[index]); - // Remove from shield zone - array.splice(index, 1); - }else{ - array[index].tapped = true; - } + makeAttack(itemDefending, itemAttacking = null){ - playerBoard[attackingCard[1]].tapped = true; - this.endAttack(); - return 1; + // If itemAttacking not defined, use the item from inEvent + if(itemAttacking == null){ + itemAttacking = inEvent[1]; } - if(defendingCard.atk <= attackingCard[0].atk){ - array.splice(index, 1); - // Need to push to grave, etc. here in future too + if(cardStatus[itemAttacking] == 'tapped'){ + alert('Cannot attack, as tapped'); + return false; } - if(attackingCard[0].atk <= defendingCard.atk){ - playerBoard.splice(attackingCard[1], 1); - }else{ - playerBoard[attackingCard[1]].tapped = true; + + switch (boardElement[itemDefending]) { + // If card on 'board' attacked + // Compare attackingCard and defendingCard + case 'board': + let atkAttacker = cardData[itemAttacking].attack; + let atkDefender = cardData[itemDefending].attack; + + // Does Attacker kill Defender + if(atkDefender <= atkAttacker){ + // TODO:Send the item to grave, boardElement = 'grave' + } + + // Does Defender kill Attacker + if(atkAttacker <= atkDefender){ + // TODO:Send the item to grave + this.endAttackFor(itemAttacking); + }else{ + // If not, end the attacker cards attack 'phase' + this.endAttackFor(itemAttacking); + } + + break; + + case 'shield': + // If the shield is tapped 'destroy' it + if(cardStatus[itemDefending] == 'tapped'){ + // Remove from shield, add to hand + // Untap, add to hand (when moving item between status, ANY ITEM. remove status) + this.destroyShield(itemDefending); + } + else{ + this.tapCard(itemDefending); + } + // End the attacker card attack 'phase' + this.endAttackFor(itemAttacking); + + break; + } + + + this.drawBoard(); + } + endAttackFor(itemAttacking){ + // Tap the card (this would check if after attack cards taps or not. + this.tapCard(itemAttacking); + + // If the item attacking was from the 'attack' event, remove the event + if(itemAttacking == inEvent[1]){ + inEvent = null; } - console.log('attacking'); - this.endAttack(); - - // If player attacked - // Compare life/remove life cards 5/10/15,1/2/3? } - endAttack(){ - attackingCard = null; - if(opponentShield.length <= 0){ - gameWin = 1; + cancelAttackFor(itemAttacking){ + if(itemAttacking != inEvent[1]){ + return false; } + + // If the card to attack is from inEvent of 'attack', remove it and its cardStatus + cardStatus[itemAttacking] = null; + inEvent = null; this.drawBoard(); } @@ -791,6 +837,23 @@ class Board{ this.drawBoard(); } } + + // HELPER METHODS, to simplify code-base for me in the future + destroyShield(itemKey){ + // Adds from 'shield' to 'hand' boardElement + // Sets the listPosition to the next in line for new boardElement + // Changes the listPosition of each item in previous boardElement + // All for same player, although below playerFrom/playerTo can be set to switch between players + // TODO: Removes any cardStatus + + //addFromBoardElement(playerFrom, fromPosition, elementFrom, elementTo, toPosition=null, playerTo=null) + this.addFromBoardElement(player[itemKey], listPosition[itemKey], boardElement[itemKey], 'hand', null, null); + } + tapCard(itemKey){ + // Set the cardStatus to tapped + cardStatus[itemKey] = 'tapped'; + // Do any other 'on tap' effects, etc. in the future + } } // TEMP!! @@ -816,14 +879,10 @@ board.drawBoard(true); //board.drawACard(3); +// Right Click, Rightclick, rightclick, right click canvas.addEventListener('contextmenu', function(event) { event.preventDefault(); - let specialEvent = false; - if(inspectCard !== null || attackingCard !== null || gameWin){ - specialEvent = true; - } - var x = event.pageX - canvasLeft, y = event.pageY - canvasTop; @@ -845,8 +904,15 @@ canvas.addEventListener('contextmenu', function(event) { switch(boardElement[itemKey]){ // Check item location, and trigger events based on it case 'board': - // Untap - cardStatus[itemKey] = null; + // TODO: If the current event is attack, right clicking same item in event + // will end the attack event + // If there's an attack event, target other cards + // If there is an event, the event is attack event, and the item currently loop + // is the same one as currently in the event + console.log(inEvent); + if(inEvent && inEvent[0] == 'attack' && itemKey == inEvent[1]){ + board.cancelAttackFor(itemKey); + } board.drawBoard(); break; case 'hand': @@ -860,21 +926,13 @@ canvas.addEventListener('contextmenu', function(event) { } } - // # PLAYER HAND - playerHand.forEach(function(card, index){ - - let clickable = card.clickable; - - if(clickableCheck(x,y,clickable) && !specialEvent){ - board.playMana(index); - board.drawBoard(); - } - }); - // Return false to prevent context opening: https://stackoverflow.com/a/4236294 + // Return false to prevent context opening: + // https://stackoverflow.com/a/4236294 return false; }, false); +// Left Click, Leftclick, leftclick, left click canvas.addEventListener('click', function(event) { console.log('EVENT LISTENER'); console.log(''); @@ -882,9 +940,23 @@ canvas.addEventListener('click', function(event) { // specialEvent used to prevent eventTriggers if something specific // is being done, attack needs to be made, inspecting card. // Prevents user from doing other actions until completed or cancelled event - let specialEvent = false; - if(inspectCard !== null || attackingCard !== null || gameWin){ - specialEvent = true; + + // If there is a 'specialEvent', and specialEvent is set to inspect + // TODO: Inspect event + if(false){ + if(inEvent && inEvent[0] == 'inspect'){ + clickable = inspectCard[0][inspectCard[1]].clickable; + + if(clickableCheck(x,y,clickable)){ + console.log('clicked inspect card'); + + }else{ + console.log('not inspected card'); + // Stop inspecting card if player clicks off it + inspectCard = null; + board.drawBoard(); + } + } } var x = event.pageX - canvasLeft, @@ -916,11 +988,33 @@ canvas.addEventListener('click', function(event) { // Check the location of element switch(boardElement[itemKey]){ // Check item location, and trigger events based on it + // TODO: Change inEvent locations, and checks elsewhere? + // TODO: Make existing mechanics ECSey case 'board': + // player/opponentBoard not seperated, as want to have + // each player able to have effects, etc. to make others attack + // etc. + + // playerBoard // Can attack - // board.startAttack(index); - // Get tapped - cardStatus[itemKey] = 'tapped'; + console.log(inEvent); + console.log(cardStatus[itemKey] != 'tapped'); + if(!inEvent && cardStatus[itemKey] != 'tapped'){ + board.startAttack(itemKey); + } + // opponentBoard + // If there's an attack event, target other cards + if(inEvent && inEvent[0] == 'attack' && inEvent[1] != itemKey){ + // Make attack on the card clicked, with card in inEvent[1] + board.makeAttack(itemKey); + } + + // If no event, and clicked an OPPONENT CARD (for now) + // inspect the card (zoom in on it) + if(!inEvent){ + board.inspectOpponentBoard(itemKey); + } + board.drawBoard(); break; case 'hand': @@ -930,96 +1024,39 @@ canvas.addEventListener('click', function(event) { board.playCardToBoard(listPosition[itemKey], 'hand', 'board', playerId, playerId, 1); board.drawBoard(); break; + case 'shield': + // TODO: + // If you have an attack, and click opponent shield, + // destroy (unless they can block, etc.) + if(inEvent && inEvent[0] == 'attack' && inEvent[1] != itemKey){ + board.makeAttack(itemKey); + } + break; } } } } - - - // Collision detection between clicked offset and clickableItems - // https://stackoverflow.com/a/9880302 - - if(inspectCard !== null){ - clickable = inspectCard[0][inspectCard[1]].clickable; - - if(clickableCheck(x,y,clickable)){ - console.log('clicked inspect card'); - - }else{ - console.log('not inspected card'); - // Stop inspecting card if player clicks off it - inspectCard = null; - board.drawBoard(); - } - } - + // Decks kept as-is for now + // TODO: boardElement realDeck, or smth and add these to the loop // # PLAYER DECK clickable = clickableItems['deckSprite']; - - // Want to loop clickables ideally, and call a function - // that's set to them for click, hover, etc. - // TODO: potentially loop all clickables, and do a check on clickable.name to differ event handling per-item - - // For now this will be fine, as it functions - if(clickableCheck(x,y,clickable) && !specialEvent){ + if(clickableCheck(x,y,clickable) && !inEvent){ board.drawACard(); } + // TODO: // # OPPONENT DECK clickable = clickableItems['deckOpponentSprite']; - - if(clickableCheck(x,y,clickable) && !specialEvent){ + if(clickableCheck(x,y,clickable) && !inEvent){ board.drawACardOpponent(); } - // # PLAYER BOARD - playerBoard.forEach(function(card, index){ - let clickable = card.clickable; - - if(clickableCheck(x,y,clickable)){ - if(attackingCard !== null && card == attackingCard[0]){ - board.endAttack(); - } - if(!specialEvent && card.tapped != true){ - board.startAttack(index); - } - board.drawBoard(); - } - }); - - // # OPPONENT BOARD - opponentBoard.forEach(function(card, index){ - let clickable = card.clickable; - - if(clickableCheck(x,y,clickable)){ - // Check if card if getting attacked - if(attackingCard !== null){ - board.makeAttack(index); - } - - if(!specialEvent){ - board.inspectOpponentBoard(index); - } - board.drawBoard(); - } - }); - // # OPPONENT SHIELD - opponentShield.forEach(function(card, index){ - let clickable = card.clickable; - - if(clickableCheck(x,y,clickable)){ - // Check if card if getting attacked - if(attackingCard !== null){ - board.makeAttack(index, opponentShield, 'opponentShield'); - } - board.drawBoard(); - } - }); - }, false); function clickableCheck(x,y,clickable=false,itemKey=false){ + // Collision detection between clicked offset and clickableItems + // https://stackoverflow.com/a/9880302 // Temp solution to add the check while the old way also exists // simultaneously. It works, so that's nice From 9890f5302bd3c03114a41b542c6624d1982cc5a8 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 13 Oct 2024 00:06:30 +0100 Subject: [PATCH 16/41] Redo basics of inspect item --- public/board.js | 53 +++++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/public/board.js b/public/board.js index 48beb1f..6b1a3f9 100644 --- a/public/board.js +++ b/public/board.js @@ -48,6 +48,8 @@ let opponentManaZone = []; // To disable drawing each time something changes let drawEachEvent = true; +let yourPlayerId = 0; // To compare click events of your/opponents cards +let viewingPlayerId = 0; // To show the board from your/opponent/teammates perspective, etc. without play permission let deckCount = 60; let deckCountOpponent = 60; @@ -57,7 +59,6 @@ const maxHandSize = 4; const maxBoardSize = 3; const maxShield = 4; -let inspectCard = null; let attackingCard = null; // Gonna need lots of refactoring, and sorting @@ -92,7 +93,7 @@ class Board{ this.drawWin(); } - this.drawInspectedCard(); + //this.drawInspectedCard(); } checkGameWin(){ @@ -665,21 +666,15 @@ class Board{ this.drawBoard(); } - inspectOpponentBoard(index){ - // Get the card data - inspectCard = [opponentBoard, index]; - + inspectCard(cardToInspect){ + // Set inspectedCard (for now) to the card itemKey + inEvent = ['inspect', cardToInspect]; this.drawBoard(); } - drawInspectedCard(){ - if(inspectCard != null){ - let positionX = canvas.width/2 - cardWidth; - let positionY = canvas.height/2 - cardHeight; - let width = cardWidth*2; - let height = cardHeight*2; - - this.drawCard(inspectCard[0], inspectCard[1], name, positionX, positionY, width, height, '#D1D100'); - console.log('inspect'); + cancelInspect(){ + if(inEvent && inEvent[0] == 'inspect'){ + inEvent = null; + this.drawBoard(); } } @@ -999,20 +994,29 @@ canvas.addEventListener('click', function(event) { // Can attack console.log(inEvent); console.log(cardStatus[itemKey] != 'tapped'); - if(!inEvent && cardStatus[itemKey] != 'tapped'){ + // yourPlayerId in for now to prevent using opponents card + // however in future the cards may be used to attack, there will be another + // check like 'canUseOpponentsBoard' or something + if(!inEvent && cardStatus[itemKey] != 'tapped' && playerId == yourPlayerId){ board.startAttack(itemKey); } // opponentBoard // If there's an attack event, target other cards - if(inEvent && inEvent[0] == 'attack' && inEvent[1] != itemKey){ + // Again yourPlayerId check for now, this time so your can't hit your own + if(inEvent && inEvent[0] == 'attack' && inEvent[1] != itemKey && playerId != yourPlayerId){ // Make attack on the card clicked, with card in inEvent[1] board.makeAttack(itemKey); } // If no event, and clicked an OPPONENT CARD (for now) + // Wants to be on option on r/l click maybe + // left click inspects then you choose play from there? // inspect the card (zoom in on it) - if(!inEvent){ - board.inspectOpponentBoard(itemKey); + if(!inEvent && playerId != yourPlayerId){ + board.inspectCard(itemKey); + } + else if(inEvent && inEvent[0] == 'inspect' && inEvent[1] == itemKey){ + board.cancelInspect(); } board.drawBoard(); @@ -1289,6 +1293,17 @@ function calculateItemSizePosition(itemKey){ height = cHeight; } + // Inspected Card + // May need to make a new itemKey for inspectedCard to loop through + if(inEvent && inEvent[0] == 'inspect' && inEvent[1] == itemKey){ + positionX = canvas.width/2 - cardWidth; + positionY = canvas.height/2 - cardHeight; + width = cardWidth*2; + height = cardHeight*2; + } + + + //console.log('cardName: '+cardData[itemKey].name+', i/listPosition: '+i+', listPosition Length: '+itemListLength); // Set the size/position of the item From 221e621fa4bea2649073a9cd43cd296e04467150 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 13 Oct 2024 11:28:39 +0100 Subject: [PATCH 17/41] Fix multiple makeAttack cases being hit --- public/board.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/public/board.js b/public/board.js index 6b1a3f9..3371d3c 100644 --- a/public/board.js +++ b/public/board.js @@ -999,6 +999,7 @@ canvas.addEventListener('click', function(event) { // check like 'canUseOpponentsBoard' or something if(!inEvent && cardStatus[itemKey] != 'tapped' && playerId == yourPlayerId){ board.startAttack(itemKey); + break; } // opponentBoard // If there's an attack event, target other cards @@ -1006,6 +1007,7 @@ canvas.addEventListener('click', function(event) { if(inEvent && inEvent[0] == 'attack' && inEvent[1] != itemKey && playerId != yourPlayerId){ // Make attack on the card clicked, with card in inEvent[1] board.makeAttack(itemKey); + break; } // If no event, and clicked an OPPONENT CARD (for now) @@ -1014,19 +1016,19 @@ canvas.addEventListener('click', function(event) { // inspect the card (zoom in on it) if(!inEvent && playerId != yourPlayerId){ board.inspectCard(itemKey); + break; } else if(inEvent && inEvent[0] == 'inspect' && inEvent[1] == itemKey){ board.cancelInspect(); + break; } - board.drawBoard(); break; case 'hand': // Can be played // Play 1 item in listPosition, from hand, to board (case from leftmost, etc) // from playerId, to playerId board.playCardToBoard(listPosition[itemKey], 'hand', 'board', playerId, playerId, 1); - board.drawBoard(); break; case 'shield': // TODO: @@ -1037,6 +1039,7 @@ canvas.addEventListener('click', function(event) { } break; } + board.drawBoard(); } } } From 54f136295d4cce3bad799bb5f60df9d4fffced54 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 13 Oct 2024 11:52:08 +0100 Subject: [PATCH 18/41] Add grave boardElement, Fix unit/unit makeAttack --- public/board.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/public/board.js b/public/board.js index 3371d3c..c1f8fdb 100644 --- a/public/board.js +++ b/public/board.js @@ -18,7 +18,7 @@ clickableItems['opponentHand'] = []; // Counters to keep track of players, and boardElements, may be changed in future // But once game starts, will be const anyway, so shouldn't need passing let players = 2; // Player, Opponent for now, but will be up to 6 players for 5v1 boss raids? -let elements = ['deck','board','hand','mana','shield']; +let elements = ['deck','board','hand','mana','shield', 'grave']; let elementsSizes = {}; // May need to have the base XY WH of board, hand, etc. stored for loop draw // Array of items, the 'Entity Manager' as such let item = []; @@ -715,17 +715,17 @@ class Board{ // If card on 'board' attacked // Compare attackingCard and defendingCard case 'board': - let atkAttacker = cardData[itemAttacking].attack; - let atkDefender = cardData[itemDefending].attack; + let atkAttacker = cardData[itemAttacking]; + let atkDefender = cardData[itemDefending]; // Does Attacker kill Defender if(atkDefender <= atkAttacker){ - // TODO:Send the item to grave, boardElement = 'grave' + this.sendToGrave(itemDefending); } // Does Defender kill Attacker if(atkAttacker <= atkDefender){ - // TODO:Send the item to grave + this.sendToGrave(itemAttacking); this.endAttackFor(itemAttacking); }else{ // If not, end the attacker cards attack 'phase' @@ -844,6 +844,13 @@ class Board{ //addFromBoardElement(playerFrom, fromPosition, elementFrom, elementTo, toPosition=null, playerTo=null) this.addFromBoardElement(player[itemKey], listPosition[itemKey], boardElement[itemKey], 'hand', null, null); } + + sendToGrave(itemKey){ + console.log('SendToGrave: '+itemKey); + //addFromBoardElement(playerFrom, fromPosition, elementFrom, elementTo, toPosition=null, playerTo=null) + this.addFromBoardElement(player[itemKey], listPosition[itemKey], boardElement[itemKey], 'grave', null, null); + } + tapCard(itemKey){ // Set the cardStatus to tapped cardStatus[itemKey] = 'tapped'; From 9e65811dd389b1fe5eadf9264fbf89bbd0d6e0df Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 13 Oct 2024 12:12:14 +0100 Subject: [PATCH 19/41] Make 'untap all' button work ECSey --- public/board.js | 38 +++++++++++++++++++++++++++++--------- public/index.html | 2 +- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/public/board.js b/public/board.js index c1f8fdb..9412b4c 100644 --- a/public/board.js +++ b/public/board.js @@ -1167,17 +1167,37 @@ function shuffleDeck(playerId){ } -function untap(array){ - console.log(array); - array.forEach(function(card, key){ - array[key].tapped = false; - }); +function untapZone(elementFrom, playerFrom){ + // TODO: Currently copy of the loop. Make the loop multi-purpose without needing to dupe the layers + // of the loop (THIS APPLIES FOR ALL USES OF THE LOOP!!) + for(let itemKey = 0; itemKey < item.length; itemKey++){ + // Get the item from the element + if(itemKey in boardElement && boardElement[itemKey] == elementFrom){ + // Check if item belongs to playerFrom + if(itemKey in player && player[itemKey] == playerFrom){ + // Just basic, if tapped, untap logic + // See why the loop shouldn't need re-adding each time? + if(cardStatus[itemKey] == 'tapped'){ + cardStatus[itemKey] = null; + } + } + } + } board.drawBoard(); } -function untapAll(){ - untap(playerMana); - untap(playerBoard); - untap(opponentShield); +function untapAllZones(currentPlayer = null){ + console.log('ut zone'); + if(currentPlayer === null){ + currentPlayer = 0; + } + for(let currentPlayer = 0; currentPlayer <= players-1; currentPlayer++){ + let elements = ['deck','board','hand','mana','shield', 'grave']; + // Loop all the elements, and utap each card in the zone + for(let element = 0; element < elements.length; element++){ + untapZone(elements[element], currentPlayer); + } + + } } function getCurrentPositionAndLength(elementName, playerId){ diff --git a/public/index.html b/public/index.html index 3a95905..d741199 100644 --- a/public/index.html +++ b/public/index.html @@ -16,7 +16,7 @@ - + From 03e68b9a8c35badffb32607beb8ec0c32e4997f7 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 13 Oct 2024 13:13:15 +0100 Subject: [PATCH 20/41] Cleanup un-used code Kept unused bits that are still to be switched to ECSey --- public/board.js | 215 +++++++++--------------------------------------- 1 file changed, 38 insertions(+), 177 deletions(-) diff --git a/public/board.js b/public/board.js index 9412b4c..33afb46 100644 --- a/public/board.js +++ b/public/board.js @@ -8,18 +8,14 @@ const cardHeight = 120; const cards = new Image(); const back = new Image(); +// TODO: Remove once decks are migrated to ECS let clickableItems = []; -// Make all clickableItems sit in the same clickableItems array -// Not needed in a child, as loops will be on arrays below -clickableItems['board'] = []; -clickableItems['hand'] = []; -clickableItems['opponentHand'] = []; // Counters to keep track of players, and boardElements, may be changed in future // But once game starts, will be const anyway, so shouldn't need passing let players = 2; // Player, Opponent for now, but will be up to 6 players for 5v1 boss raids? let elements = ['deck','board','hand','mana','shield', 'grave']; -let elementsSizes = {}; // May need to have the base XY WH of board, hand, etc. stored for loop draw +let elementsSizes = {}; // TODO: May need to have the base XY WH of board, hand, etc. stored for loop draw // Array of items, the 'Entity Manager' as such let item = []; let itemCount = 0; @@ -35,32 +31,25 @@ let player = {}; let listPosition = {}; let inEvent = null; -let playerHand = []; -let opponentHand = []; -let playerBoard = []; -let opponentBoard = []; +// TODO: Do something else ECSey, think most logic for this is about let playerDeck = []; let opponentDeck = []; -let playerShield = []; -let opponentShield = []; +// TODO: Re-implement, then remove existing code let playerMana = []; -let opponentManaZone = []; +let playerHand = []; // To disable drawing each time something changes -let drawEachEvent = true; +let drawEachEvent = true; // For disabling draw each time and only occuring where I want to test let yourPlayerId = 0; // To compare click events of your/opponents cards let viewingPlayerId = 0; // To show the board from your/opponent/teammates perspective, etc. without play permission -let deckCount = 60; -let deckCountOpponent = 60; +let deckCount = 35; +let deckCountOpponent = 35; -let cardsInOpponentsHand = 0; const maxHandSize = 4; const maxBoardSize = 3; const maxShield = 4; -let attackingCard = null; - // Gonna need lots of refactoring, and sorting class Board{ constructor(){ @@ -81,8 +70,6 @@ class Board{ // Room Name ctx.fillText(name, 0, 10); - this.drawCardsOnBoard(); - this.drawDecks(); this.drawPlayerNames('Nathan', 'Evil Nathan'); @@ -92,17 +79,11 @@ class Board{ if(this.checkGameWin == true){ this.drawWin(); } - - //this.drawInspectedCard(); } checkGameWin(){ // TODO: Change logic to ECSey, and move into main loop (for other win-cons besides direct attack) - if(false){ - if(opponentShield.length <= 0){ - return true; - } - } + //if(opponentShield.length <= 0){return true; return false; } @@ -129,9 +110,7 @@ class Board{ ctx.fillText(playerName, 50, canvas.height - 50); // Opponent's Name - if(!opponentName){ - // Just clear the name - }else{ + if(opponentName){ ctx.fillText(opponentName, canvas.width - (ctx.measureText(opponentName).width + 50), 50); } } @@ -310,9 +289,9 @@ class Board{ array[arrayKey]['clickable'].draw(); // Add image - // half circle for unit Set start angle to 0 and end angle to Math.PI. - // Ellipse for token (near full size) - // Octagon for spell + // TODO:half circle for unit Set start angle to 0 and end angle to Math.PI. + // TODO:Ellipse for token (near full size) + // TODO:Octagon for spell let cardImageContainer = new Shape({ shape: 'semi', name: 'cardImageContainer_'+name, @@ -461,13 +440,12 @@ class Board{ } addFromBoardElement(playerFrom, fromPosition, elementFrom, elementTo, toPosition=null, playerTo=null){ + // Move itemKey fromPosition in elementFrom to toPosition in elementTo + // can also switch item between players (of from and to supplied) if(playerTo == null){ playerTo = playerFrom; } - // Move itemKey fromPosition in elementFrom to toPosition in elementTo - // Can also switch item between players - // Loop all items, get the item with boardElement elementFrom and player playerFrom for(let itemKey = 0; itemKey < item.length; itemKey++){ @@ -543,56 +521,17 @@ class Board{ } // Draw a card, traditional TCG - drawACard(cardsToDraw = 1){ - for(let draw = 0; draw < cardsToDraw; draw++){ - // Check there's space in hand - // TODO: Normalise this for all element/player combos - let elementLength = getCurrentPositionAndLength('hand', 0)[1]; - if(elementLength >= maxHandSize){ - alert('Hand full '+elementLength+'/'+maxHandSize); - return 0; - } - // Move from player0, position 0 (top) of deck, to hand - this.addFromBoardElement(0, 0, 'deck', 'hand', null, null); - } - } - - drawACardOpponent(cardsToDraw = 1){ + drawACard(playerId, cardsToDraw = 1){ for(let draw = 0; draw < cardsToDraw; draw++){ // Move from player1, position 0 (top) of deck, to hand // Check there's space in hand - // TODO: Normalise this for all element/player combos - let elementLength = getCurrentPositionAndLength('hand', 1)[1]; + let elementLength = getCurrentPositionAndLength('hand', playerId)[1]; if(elementLength >= maxHandSize){ alert('Hand full '+elementLength+'/'+maxHandSize); return 0; } - this.addFromBoardElement(1, 0, 'deck', 'hand', null, null); - } - } - - - drawCardsOnBoard(){ - // DUPE OF DRAW PLAYER HAND FOR NOW!!! - for (let i = 0; i < playerBoard.length; i++) { - - let name = 'cardOnBoard_'+(i+1); - - let cardPadding = 10; - let fill = '#'+i+i+'CC00'; - - // TODO: fix positionX, actually have some maffs - let positionX = canvas.width/2 - (cardWidth * (playerBoard.length - (i+1)) - (cardPadding * (i+1))); - let positionY = canvas.height - cardHeight-30-(cardHeight); - let width = cardWidth; - let height = cardHeight; - let border = false; - - if(attackingCard !== null && playerBoard[i].name == attackingCard[0].name){ - border = '#FF0000'; - } - this.drawCard(playerBoard, i, name, positionX, positionY, width, height, fill, border); + this.addFromBoardElement(playerId, 0, 'deck', 'hand', null, null); } } @@ -678,13 +617,10 @@ class Board{ } } + startAttack(itemAttacking){ // Selects the card that will be attacking - // Stop other actions besides selecting opponent/opponent unit - // Can cancel, will do later // Rename to attack intent? - startAttack(itemAttacking){ - // Can probably combine attacking/inspect, and set another array element to 'attacking', 'inspecting', etc. - + // Do error/legal checks here if(cardStatus[itemAttacking] == 'tapped'){ alert('Cannot attack, as tapped'); @@ -693,13 +629,14 @@ class Board{ // Set event inEvent = ['attack', itemAttacking]; // Set the status of card to attacking for drawing. - // In future this may be what's used for check (or other in case you can attack with multiple units at once) + // TODO:In future this may be what's used for check (or other in case you can attack with multiple units at once) cardStatus[itemAttacking] = 'attacking'; this.drawBoard(); } // Do the attack makeAttack(itemDefending, itemAttacking = null){ + // TODO: Check if mana owner has any 'block', etc. first, then prevent if so // If itemAttacking not defined, use the item from inEvent if(itemAttacking == null){ @@ -789,24 +726,6 @@ class Board{ // Move from player, position 0 (top) of deck, to hand (next available position) this.addFromBoardElement(playerId, fromPosition, fromElement, 'shield', null, null); } - - if(false){ - for(let shieldNo = 0; shieldNo < shieldsToPlay; shieldNo++){ - if(playerShield.length >= maxShield){ - alert('Shield zone full '+playerShield.length+'/'+maxShield); - return 0; - } - - // Random card from deck, remove from deck, add to hand - let cardToDraw = Math.floor(Math.random() * deckCount); - let cardDrawn = playerDeck[cardToDraw]; - // Remove from deck - playerDeck.splice(cardToDraw, 1); - // Add to shield zone - playerShield.push(cardDrawn); - this.drawBoard(); - } - } } playMana(fromPosition, fromElement, cardsToPlay = 1){ @@ -814,23 +733,6 @@ class Board{ // TODO: FOR ALL addFromBoardElements, if 'fromPosition' not passed get the // fromPosition and boardElementFrom from the itemId (will need to change to pass this) this.addFromBoardElement(0, fromPosition, fromElement, 'mana', null, null); - - if(false){ - let manaCard = null; - if(fromDeck){ - let cardToDraw = Math.floor(Math.random() * deckCount); - manaCard = playerDeck[cardToDraw]; - // Remove from deck - playerDeck.splice(cardToDraw, 1); - }else{ - manaCard = playerHand[index]; - playerHand.splice(index, 1); - } - - playerMana.push(manaCard); - - this.drawBoard(); - } } // HELPER METHODS, to simplify code-base for me in the future @@ -858,27 +760,19 @@ class Board{ } } -// TEMP!! +// TODO: TEMP!! Replace soon createDeckList(playerDeck, deckCount, 0); createDeckList(opponentDeck, deckCountOpponent, 1); // Run board commands here for testing let board = new Board; -//board.initBoard(); -//shuffleDeck(0); -//shuffleDeck(1); - -//board.drawBoard(); -// Play 4 shield from position 0 (top) of deck, for player 0 (you) -// TODO:May want to change this to play from opponents deck, or hand, etc. for future -// That will likely be a while though I assume? -board.playShield(0, 'deck', 0, 4); -board.playShield(0, 'deck', 1, 4); -//board.playShieldOpponent(4); +// Play 4 shield from top (0) of each players deck +for(let currentPlayer = 0; currentPlayer <= players-1; currentPlayer++){ + board.playShield(0, 'deck', currentPlayer, 4); +} board.drawBoard(true); -//board.drawACard(3); // Right Click, Rightclick, rightclick, right click @@ -901,7 +795,6 @@ canvas.addEventListener('contextmenu', function(event) { // Only want to happen once (for now) // Maybe in future add to hand would trigger another event if there's an effect? - console.log(boardElement[itemKey]); // Check the location of element switch(boardElement[itemKey]){ // Check item location, and trigger events based on it @@ -911,7 +804,6 @@ canvas.addEventListener('contextmenu', function(event) { // If there's an attack event, target other cards // If there is an event, the event is attack event, and the item currently loop // is the same one as currently in the event - console.log(inEvent); if(inEvent && inEvent[0] == 'attack' && itemKey == inEvent[1]){ board.cancelAttackFor(itemKey); } @@ -936,30 +828,6 @@ canvas.addEventListener('contextmenu', function(event) { // Left Click, Leftclick, leftclick, left click canvas.addEventListener('click', function(event) { - console.log('EVENT LISTENER'); - console.log(''); - - // specialEvent used to prevent eventTriggers if something specific - // is being done, attack needs to be made, inspecting card. - // Prevents user from doing other actions until completed or cancelled event - - // If there is a 'specialEvent', and specialEvent is set to inspect - // TODO: Inspect event - if(false){ - if(inEvent && inEvent[0] == 'inspect'){ - clickable = inspectCard[0][inspectCard[1]].clickable; - - if(clickableCheck(x,y,clickable)){ - console.log('clicked inspect card'); - - }else{ - console.log('not inspected card'); - // Stop inspecting card if player clicks off it - inspectCard = null; - board.drawBoard(); - } - } - } var x = event.pageX - canvasLeft, y = event.pageY - canvasTop; @@ -997,12 +865,8 @@ canvas.addEventListener('click', function(event) { // each player able to have effects, etc. to make others attack // etc. - // playerBoard - // Can attack - console.log(inEvent); - console.log(cardStatus[itemKey] != 'tapped'); // yourPlayerId in for now to prevent using opponents card - // however in future the cards may be used to attack, there will be another + // TODO:the cards may be used to attack, there will be another // check like 'canUseOpponentsBoard' or something if(!inEvent && cardStatus[itemKey] != 'tapped' && playerId == yourPlayerId){ board.startAttack(itemKey); @@ -1017,7 +881,7 @@ canvas.addEventListener('click', function(event) { break; } - // If no event, and clicked an OPPONENT CARD (for now) + // If no event, and clicked an TODO:OPPONENT CARD (for now) // Wants to be on option on r/l click maybe // left click inspects then you choose play from there? // inspect the card (zoom in on it) @@ -1032,13 +896,10 @@ canvas.addEventListener('click', function(event) { break; case 'hand': - // Can be played - // Play 1 item in listPosition, from hand, to board (case from leftmost, etc) - // from playerId, to playerId + // TODO: Ensure it can be played board.playCardToBoard(listPosition[itemKey], 'hand', 'board', playerId, playerId, 1); break; case 'shield': - // TODO: // If you have an attack, and click opponent shield, // destroy (unless they can block, etc.) if(inEvent && inEvent[0] == 'attack' && inEvent[1] != itemKey){ @@ -1056,14 +917,14 @@ canvas.addEventListener('click', function(event) { // # PLAYER DECK clickable = clickableItems['deckSprite']; if(clickableCheck(x,y,clickable) && !inEvent){ - board.drawACard(); + board.drawACard(0); } // TODO: // # OPPONENT DECK clickable = clickableItems['deckOpponentSprite']; if(clickableCheck(x,y,clickable) && !inEvent){ - board.drawACardOpponent(); + board.drawACard(1); } }, false); @@ -1106,6 +967,8 @@ function clickableCheck(x,y,clickable=false,itemKey=false){ // TEMP: Create a deck of X different cards that can be drawn/played // for UI development, will be done on server and not shown to clients +// TODO: Randomly create a deck from objects stored in file (for now) then DB +// 3 of each card max, and likely one colour too for time being function createDeckList(deck, deckCount, playerId){ for(let i = 0; i < deckCount; i++){ // Randomise colour @@ -1113,7 +976,6 @@ function createDeckList(deck, deckCount, playerId){ let effect = Math.floor(Math.random() * 5); if(effect == 0){ effect = 'effect here'; } else{ effect = null } - item.push(itemCount); boardElement[itemCount] = 'deck'; cardData[itemCount] = { @@ -1134,6 +996,8 @@ function createDeckList(deck, deckCount, playerId){ itemCount++; } + + //TODO: shuffleDeck(0); Make shuffleDeck work, and call after created the deck (for now) } function shuffleDeck(playerId){ @@ -1186,7 +1050,6 @@ function untapZone(elementFrom, playerFrom){ board.drawBoard(); } function untapAllZones(currentPlayer = null){ - console.log('ut zone'); if(currentPlayer === null){ currentPlayer = 0; } @@ -1264,7 +1127,7 @@ function calculateItemSizePosition(itemKey){ height = cardHeight; } if(itemPlayer == 1 && itemElement == 'mana'){ - + // TODO: Opponent Mana } if(itemPlayer == 1 && itemElement == 'shield'){ let fromX = canvas.width-60; @@ -1324,7 +1187,7 @@ function calculateItemSizePosition(itemKey){ } // Inspected Card - // May need to make a new itemKey for inspectedCard to loop through + // TODO: May need to make a new itemKey for inspectedCard to loop through if(inEvent && inEvent[0] == 'inspect' && inEvent[1] == itemKey){ positionX = canvas.width/2 - cardWidth; positionY = canvas.height/2 - cardHeight; @@ -1332,8 +1195,6 @@ function calculateItemSizePosition(itemKey){ height = cardHeight*2; } - - //console.log('cardName: '+cardData[itemKey].name+', i/listPosition: '+i+', listPosition Length: '+itemListLength); // Set the size/position of the item From 3ed1be6bc87cdbc8aaa4ce243245d8bc4e2a8bb1 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 13 Oct 2024 13:28:54 +0100 Subject: [PATCH 21/41] Fix gameWin --- public/board.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/public/board.js b/public/board.js index 33afb46..72534cd 100644 --- a/public/board.js +++ b/public/board.js @@ -76,14 +76,14 @@ class Board{ this.drawCardsECS(); // Atop most everything atm for testing - if(this.checkGameWin == true){ + if(this.checkGameWin() == true){ this.drawWin(); } } checkGameWin(){ - // TODO: Change logic to ECSey, and move into main loop (for other win-cons besides direct attack) - //if(opponentShield.length <= 0){return true; + // If opponent shield is 0 then you win TODO: Otherwincons, check w/l for each player + if(this.remainingShieldCount(1) <= 0){return true;} return false; } @@ -758,6 +758,9 @@ class Board{ cardStatus[itemKey] = 'tapped'; // Do any other 'on tap' effects, etc. in the future } + remainingShieldCount(playerId){ + return getCurrentPositionAndLength('shield', playerId)[1]; + } } // TODO: TEMP!! Replace soon From 572fc1b40b4cc10ad36117f9c5cf1106edc5ce2d Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 13 Oct 2024 13:29:54 +0100 Subject: [PATCH 22/41] Add untapCard helper --- public/board.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/public/board.js b/public/board.js index 72534cd..02acb6d 100644 --- a/public/board.js +++ b/public/board.js @@ -758,6 +758,10 @@ class Board{ cardStatus[itemKey] = 'tapped'; // Do any other 'on tap' effects, etc. in the future } + untapCard(itemKey){ + cardStatus[itemKey] = null; + // Do any other 'on tap' effects, etc. in the future + } remainingShieldCount(playerId){ return getCurrentPositionAndLength('shield', playerId)[1]; } @@ -1045,7 +1049,7 @@ function untapZone(elementFrom, playerFrom){ // Just basic, if tapped, untap logic // See why the loop shouldn't need re-adding each time? if(cardStatus[itemKey] == 'tapped'){ - cardStatus[itemKey] = null; + board.untapCard(itemKey); } } } From 10c825a7d87e266d3261ebe72e5370ffd27c7ad5 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 13 Oct 2024 13:35:03 +0100 Subject: [PATCH 23/41] Add status removal when item changes boardElement --- public/board.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/public/board.js b/public/board.js index 02acb6d..7149b1b 100644 --- a/public/board.js +++ b/public/board.js @@ -478,6 +478,8 @@ class Board{ this.moveElementPositions(0, elementFrom, fromPosition, playerFrom); //console.log(JSON.stringify(boardElement)); //console.log(JSON.stringify(listPosition)); + + this.removeItemStatus(itemKey); this.drawBoard(); return 1; // Got a loop that calls a loop, and checks the new values atm, so this keeps counting down @@ -765,6 +767,10 @@ class Board{ remainingShieldCount(playerId){ return getCurrentPositionAndLength('shield', playerId)[1]; } + removeItemStatus(itemKey){ + // TODO: Remove status of card, and do/don't do effect depending on locationTo/locationFrom? + cardStatus[itemKey] = null; + } } // TODO: TEMP!! Replace soon From 73a44512ef80c4a50bbd3f0ef437769ce84fb646 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 13 Oct 2024 13:49:25 +0100 Subject: [PATCH 24/41] Add shield destroy check logic --- public/board.js | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/public/board.js b/public/board.js index 7149b1b..1e5cedf 100644 --- a/public/board.js +++ b/public/board.js @@ -743,10 +743,38 @@ class Board{ // Sets the listPosition to the next in line for new boardElement // Changes the listPosition of each item in previous boardElement // All for same player, although below playerFrom/playerTo can be set to switch between players - // TODO: Removes any cardStatus + + // TODO:Check if shield can be destroyed (instantly, i.e. poisontouch, or some mechanic/spell akin) + // Check the shield is not tapped, if not can't be destroyed + if(!this.isTapped(itemKey)){ + alert('Shield not tapped, cannot be destroyed'); + return false; + } + // Check if all other shields are tapped before destroying the shield + // TODO: Normalise the loop!!! + // Think this can be done by looping what's needed, then returning itemKeys in array for each + // item that hits criteria, then looping that new array and applying logic? + + // Loop all items, get the item with boardElement elementFrom and player playerFrom + for(let itemKey = 0; itemKey < item.length; itemKey++){ + // Get the item from the element + if(itemKey in boardElement && boardElement[itemKey] == 'shield'){ + // Check each shield on the board of the owner of shield being attacked + if(itemKey in player && player[itemKey] == player[itemKey]){ + // If ANY of their shields are untapped, you can't destroy target + if(cardStatus[itemKey] != 'tapped'){ + alert('There is an untapped shield, cannot destroy target'); + return false; + } + } + } + } + + // Shield is now destroyed, move it from shield to owners hand (for the catchup mechanic) //addFromBoardElement(playerFrom, fromPosition, elementFrom, elementTo, toPosition=null, playerTo=null) this.addFromBoardElement(player[itemKey], listPosition[itemKey], boardElement[itemKey], 'hand', null, null); + return true; } sendToGrave(itemKey){ @@ -771,6 +799,10 @@ class Board{ // TODO: Remove status of card, and do/don't do effect depending on locationTo/locationFrom? cardStatus[itemKey] = null; } + isTapped(itemKey){ + if(cardStatus[itemKey] == 'tapped'){ return true; } + return false; + } } // TODO: TEMP!! Replace soon From 96d21acc57ba01e2c39553784222d042e6cc6496 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 13 Oct 2024 14:38:06 +0100 Subject: [PATCH 25/41] Fix deck count --- public/board.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/board.js b/public/board.js index 1e5cedf..ddba2e1 100644 --- a/public/board.js +++ b/public/board.js @@ -434,7 +434,7 @@ class Board{ // Draw deck count text // TODO: Center in the circle ctx.fillStyle = '#000'; - ctx.fillText(deckLength, textx, texty); + ctx.fillText(deckLength+1, textx, texty); } } From f209af082bb4fe489dfc460997edf3616ea92355 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 13 Oct 2024 15:29:08 +0100 Subject: [PATCH 26/41] ECSey LOOP NORMALISATION --- public/board.js | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/public/board.js b/public/board.js index ddba2e1..a771697 100644 --- a/public/board.js +++ b/public/board.js @@ -439,6 +439,114 @@ class Board{ } + // boardElement, cardData?, position?, size?, cardStatus, player, listPosition + ECSLoop(boardElementId = null, playerId = null, cardStatusId = null, listPositionId = null){ + // So, the intent here is to normalise my nested loop I keep duping (parts of) + // This will recieve each piece of content that can be stored in each ECS element + // Then will loop each individually, setting a new array to be returned + // This new array will then be used for tapping, untapping, moving positions, etc. + + // This is the 'core' of the loop, as it'll keep changing what's in it, removing + // elements at each step. I.e. Will check boardElement for 'mana', removing all other boardElements + // Then with just the 'mana' elements will check the player. OR can return all mana, OR all player items + let newItems = []; + let tempArray = []; + + // Set to all items in itemArray to start + newItems = item; + + //let elements = ['deck','board','hand','mana','shield', 'grave']; + // Stuff to be looped, and compared + //let boardElement = {}; + //let cardData = {}; + //let position = {}; + //let size = {}; + //let cardStatus = {}; // tapped, attacking, inspected, untargettable (TODO:maybe used this instead of inEvent later) + //let player = {}; + //let listPosition = {}; + + // These have been re-ordered to try to minise looping + // Example, player in theory halfs the cards instantly, whereas boardElement deck, may do little + // boardElement often will be better though, but??? + + // PLAYER + if(playerId !== null){ + for(let newItem = 0; newItem < newItems.length; newItem++){ + let itemKey = newItems[newItem]; + // If the playerId of item shares the passed playerId + if(playerId == player[itemKey]){ + tempArray.push(newItems[newItem]); + } + } + // Set newItems to what remains in tempArray + newItems = tempArray; + } + // Reset tempArray so it can be reused + tempArray = []; + + // CARD STATUS + if(cardStatusId !== null){ + for(let newItem = 0; newItem < newItems.length; newItem++){ + let itemKey = newItems[newItem]; + // If the playerId of item shares the passed playerId + if(cardStatusId == cardStatus[itemKey]){ + tempArray.push(newItems[newItem]); + } + } + // Set newItems to what remains in tempArray + newItems = tempArray; + } + // Reset tempArray so it can be reused + tempArray = []; + + // LIST POSITION + if(listPositionId !== null){ + for(let newItem = 0; newItem < newItems.length; newItem++){ + let itemKey = newItems[newItem]; + // If the playerId of item shares the passed playerId + if(listPositionId == listPosition[itemKey]){ + tempArray.push(newItems[newItem]); + } + } + // Set newItems to what remains in tempArray + newItems = tempArray; + } + // Reset tempArray so it can be reused + tempArray = []; + + + // BOARD ELEMENT + // Loop items for boardElement of elementType passed + // Only do the loop if the element type was passed too, no reason to waste resources + if(boardElementId !== null){ + for(let newItem = 0; newItem < newItems.length; newItem++){ + // Add the itemKey to tempArray + // itemKey can be different to the array's elementId, and we want the original itemKey, + // not the new elementId, as that would then add the wrong item + + // Set the itemKey, so things make sense + let itemKey = newItems[newItem]; //newItems[0] could be itemKey 12, so want the content + + // If the boardElement of item shares the passed boardElement add it to current return + if(boardElementId == boardElement[itemKey]){ + tempArray.push(newItems[newItem]); + } + } + + // Set newItems to what remains in tempArray + newItems = tempArray; + } + // Reset tempArray so it can be reused + tempArray = []; + + return newItems; + + // TODO: May look at restructuring this again. Maybe one loop with each check against + // the element data passed. Depends on which seems fastest, may do a compare on a large + // dataset to see + // TODO: ALSO in different func, Something like x.element.player.status to return the itemKey? + } + addFromBoardElement(playerFrom, fromPosition, elementFrom, elementTo, toPosition=null, playerTo=null){ // Move itemKey fromPosition in elementFrom to toPosition in elementTo // can also switch item between players (of from and to supplied) @@ -607,6 +715,7 @@ class Board{ this.drawBoard(); } + inspectCard(cardToInspect){ // Set inspectedCard (for now) to the card itemKey inEvent = ['inspect', cardToInspect]; @@ -1247,4 +1356,15 @@ function calculateItemSizePosition(itemKey){ position[itemKey] = [positionX,positionY]; } +function ECSLoopTest(){ + // boardElement, player, cardStatus, listPosition + // TODO: ?cardData?, position?, size? + let boardElementId = 'board'; + let playerId = 0; + let cardStatusId = null; + let listPositionId = null; + let items = board.ECSLoop(boardElementId, playerId, cardStatusId, listPositionId); + console.log('Items in boardElement: '+boardElementId+' player: '+playerId+' cardStatus: '+cardStatusId+' listPosition: '+listPositionId); + console.log(items); +} From 6458e7d85aa692988f99e39803013db69ad5e4c3 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 13 Oct 2024 16:04:28 +0100 Subject: [PATCH 27/41] Switch loops to normalised loop --- public/board.js | 158 ++++++++++++++++-------------------------------- 1 file changed, 51 insertions(+), 107 deletions(-) diff --git a/public/board.js b/public/board.js index a771697..e7237ff 100644 --- a/public/board.js +++ b/public/board.js @@ -554,47 +554,29 @@ class Board{ playerTo = playerFrom; } + // First (and only) item returned is the key thins should be done with + let itemKey = this.ECSLoop(elementFrom, playerFrom, null, fromPosition)[0]; + if(listPosition[itemKey] == fromPosition){ + // Check if a toPostion supplied + if(toPosition == null){ + // Get the new position of item based on new boardElement + toPosition = getCurrentPositionAndLength(elementTo, playerTo)[0]+1 + } + //console.log('itemKey: '+itemKey+' fromPosition: '+fromPosition+' elementFrom: '+elementFrom+' elementTo: '+elementTo+' toPosition: '+toPosition+' playerFrom: '+playerFrom+' playerTo: '+playerTo); - // Loop all items, get the item with boardElement elementFrom and player playerFrom - for(let itemKey = 0; itemKey < item.length; itemKey++){ - // Get the item from the element - if(itemKey in boardElement && boardElement[itemKey] == elementFrom){ - // Check if item belongs to playerFrom - if(itemKey in player && player[itemKey] == playerFrom){ - - // Get item based on fromPosition listPosition - if(listPosition[itemKey] == fromPosition){ - // Check if a toPostion supplied (likely won't be, dunno if I'll do this) - if(toPosition == null){ - // Get the new position of item based on new boardElement - toPosition = getCurrentPositionAndLength(elementTo, playerTo)[0]+1 - //console.log(toPosition); - } - //console.log('itemKey: '+itemKey+' fromPosition: '+fromPosition+' elementFrom: '+elementFrom+' elementTo: '+elementTo+' toPosition: '+toPosition+' playerFrom: '+playerFrom+' playerTo: '+playerTo); - listPosition[itemKey] = toPosition; - - // Move from elementFrom to elementTo - //console.log('elementTo: '+elementTo); - //console.log(boardElement[itemKey]); - boardElement[itemKey] = elementTo; - //console.log(itemKey); - //console.log(boardElement[itemKey]); - - // Move down(0) the positions of elementFrom, from fromPosition for player - //console.log(JSON.stringify(boardElement)); - //console.log(JSON.stringify(listPosition)); - this.moveElementPositions(0, elementFrom, fromPosition, playerFrom); - //console.log(JSON.stringify(boardElement)); - //console.log(JSON.stringify(listPosition)); - - this.removeItemStatus(itemKey); - this.drawBoard(); - return 1; // Got a loop that calls a loop, and checks the new values atm, so this keeps counting down + // Move item to it's new position + listPosition[itemKey] = toPosition; + // Move item to it's new element + boardElement[itemKey] = elementTo; - } - } - } + // Move down(0) the positions of elementFrom, from fromPosition for player + this.moveElementPositions(0, elementFrom, fromPosition, playerFrom); + + this.removeItemStatus(itemKey); + this.drawBoard(); + return 1; // Got a loop that calls a loop, and checks the new values atm, so this keeps counting down } + } moveElementPositions(direction, elementFrom, fromPosition, playerFrom){ @@ -604,31 +586,18 @@ class Board{ // Loop the elementFrom, and move positions for anything after // item taken from position 34, 35..60 need to be moved down to 34..59 - // For each item - for(let itemKey = 0; itemKey < item.length; itemKey++){ - // If boardElement is elementFrom - if(itemKey in boardElement && boardElement[itemKey] == elementFrom){ - // And from the playerFrom (id) - if(itemKey in player && player[itemKey] == playerFrom){ - //console.log(elementFrom); - //console.log(boardElement[itemKey]); - //console.log(listPosition[itemKey]); - //console.log(itemKey); - if(listPosition[itemKey] > fromPosition){ - //console.log('position: '+listPosition[itemKey]+' fromPosition: '+fromPosition); - // Move items up, i.e. added to top of deck - if(direction){ - listPosition[itemKey]++; - } - // Move items down, i.e. taken from top of deck - listPosition[itemKey]--; - } - + let items = this.ECSLoop(elementFrom, playerFrom, null, null); + for(let item = 0; item < items.length; item++){ + let itemKey = items[item]; + if(listPosition[itemKey] > fromPosition){ + // Move items up, i.e. added to top of deck + if(direction){ + listPosition[itemKey]++; } + // Move items down, i.e. taken from top of deck + listPosition[itemKey]--; } } - //console.log(listPosition); - } // Draw a card, traditional TCG drawACard(playerId, cardsToDraw = 1){ @@ -860,28 +829,19 @@ class Board{ alert('Shield not tapped, cannot be destroyed'); return false; } - // Check if all other shields are tapped before destroying the shield - // TODO: Normalise the loop!!! - // Think this can be done by looping what's needed, then returning itemKeys in array for each - // item that hits criteria, then looping that new array and applying logic? - - // Loop all items, get the item with boardElement elementFrom and player playerFrom - for(let itemKey = 0; itemKey < item.length; itemKey++){ - // Get the item from the element - if(itemKey in boardElement && boardElement[itemKey] == 'shield'){ - // Check each shield on the board of the owner of shield being attacked - if(itemKey in player && player[itemKey] == player[itemKey]){ - // If ANY of their shields are untapped, you can't destroy target - if(cardStatus[itemKey] != 'tapped'){ - alert('There is an untapped shield, cannot destroy target'); - return false; - } - } + // Get all shields, that belong to the player whose shield was targetted. + // Check if they're all tapped before destroying the target + let items = this.ECSLoop('shield', player[itemKey], null, null); + for(let item = 0; item < items.length; item++){ + let itemKey = items[item]; + // If ANY of their shields are untapped, you can't destroy target + if(cardStatus[itemKey] != 'tapped'){ + alert('There is an untapped shield, cannot destroy target'); + return false; } } // Shield is now destroyed, move it from shield to owners hand (for the catchup mechanic) - //addFromBoardElement(playerFrom, fromPosition, elementFrom, elementTo, toPosition=null, playerTo=null) this.addFromBoardElement(player[itemKey], listPosition[itemKey], boardElement[itemKey], 'hand', null, null); return true; } @@ -942,6 +902,7 @@ canvas.addEventListener('contextmenu', function(event) { continue; } + // TODO: Normalise this too, may need to change how size+position work? // Check the item has a size and position if(itemKey in size && itemKey in position){ // Compare the event XY position to the item @@ -992,6 +953,7 @@ canvas.addEventListener('click', function(event) { // TODO:Maybe write this into a function? If XY WH is hit return true, and the itemKey // then it can be re-used in contextclick, hover, etc without rewrite //console.log('X: '+x+' Y: '+y); + // TODO: Normalise this too for(let itemKey = 0; itemKey < item.length; itemKey++){ if(elements[itemKey] == 'deck'){ @@ -1186,20 +1148,10 @@ function shuffleDeck(playerId){ } function untapZone(elementFrom, playerFrom){ - // TODO: Currently copy of the loop. Make the loop multi-purpose without needing to dupe the layers - // of the loop (THIS APPLIES FOR ALL USES OF THE LOOP!!) - for(let itemKey = 0; itemKey < item.length; itemKey++){ - // Get the item from the element - if(itemKey in boardElement && boardElement[itemKey] == elementFrom){ - // Check if item belongs to playerFrom - if(itemKey in player && player[itemKey] == playerFrom){ - // Just basic, if tapped, untap logic - // See why the loop shouldn't need re-adding each time? - if(cardStatus[itemKey] == 'tapped'){ - board.untapCard(itemKey); - } - } - } + let items = board.ECSLoop(elementFrom, playerFrom, null, null); + for(let item = 0; item < items.length; item++){ + let itemKey = items[item]; + if(board.isTapped(itemKey)){ board.untapCard(itemKey); } } board.drawBoard(); } @@ -1220,24 +1172,16 @@ function getCurrentPositionAndLength(elementName, playerId){ let highestListPosition = 0; let length = 0; - // Loop all the items - // Think making the for loop, and the if into something to be called that fires functions would be smart? - for(let itemKey = 0; itemKey < item.length; itemKey++){ - // Check the item is the correct boardElement - // 'key' in 'object' - if(itemKey in boardElement && boardElement[itemKey] == elementName){ - // Check if item belongs to the player - if(itemKey in player && player[itemKey] == playerId){ - if(listPosition[itemKey]){ - if(listPosition[itemKey] >= highestListPosition){ - highestListPosition = listPosition[itemKey]; - length++; - } - } + let items = board.ECSLoop(elementName, playerId, null, null); + for(let item = 0; item < items.length; item++){ + let itemKey = items[item]; - } + if(listPosition[itemKey] >= highestListPosition){ + highestListPosition = listPosition[itemKey]; + length++; } + } return [highestListPosition, length]; From 9754497895252c20d0de2a9d7015d3826a9f2523 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 13 Oct 2024 18:29:37 +0100 Subject: [PATCH 28/41] Add ECSeyey... shuffleDeck --- public/board.js | 62 +++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/public/board.js b/public/board.js index e7237ff..51ff2a4 100644 --- a/public/board.js +++ b/public/board.js @@ -434,7 +434,7 @@ class Board{ // Draw deck count text // TODO: Center in the circle ctx.fillStyle = '#000'; - ctx.fillText(deckLength+1, textx, texty); + ctx.fillText(deckLength, textx, texty); } } @@ -874,13 +874,13 @@ class Board{ } } +// Run board commands here for testing +let board = new Board; + // TODO: TEMP!! Replace soon createDeckList(playerDeck, deckCount, 0); createDeckList(opponentDeck, deckCountOpponent, 1); -// Run board commands here for testing -let board = new Board; - // Play 4 shield from top (0) of each players deck for(let currentPlayer = 0; currentPlayer <= players-1; currentPlayer++){ board.playShield(0, 'deck', currentPlayer, 4); @@ -1113,37 +1113,39 @@ function createDeckList(deck, deckCount, playerId){ itemCount++; } - //TODO: shuffleDeck(0); Make shuffleDeck work, and call after created the deck (for now) + // Shuffle the deck straight away after generating/loading it in + shuffleDeck(playerId); } function shuffleDeck(playerId){ - let tempDeck = []; - for(let itemKey = 0; itemKey < item.length; itemKey++){ - // Check if item is in deck - // 'key' in 'object' - if(itemKey in boardElement && boardElement[itemKey] == 'deck'){ - // Check if item belongs to opponent - if(itemKey in player && player[itemKey] == playerId){ - // This will shuffle, but not from OG deck state. - // Will need to get the listPosition and order by that first - //console.log(itemKey); - tempDeck.push(itemKey); - } - } + + // Create a tempDeck array of same length of the player deck + let deckLength = getCurrentPositionAndLength('deck', playerId)[1]; + let tempDeck = Array.from(Array(deckLength).keys()) + + // Loop the tempDeck and shuffle + // https://stackoverflow.com/a/73603221 + for(let i = 0; i < deckLength; i++){ + // picks the random number between 0 and length of the deck + let shuffle = Math.floor(Math.random() * (tempDeck.length)); + // swap the current listPosition with a random one with the deck count + [ tempDeck[i], tempDeck[shuffle] ] = [ tempDeck[shuffle], tempDeck[i] ]; } - // Temporary shuffle until algo selected/written - let id, shuffledPile, i; - console.log(tempDeck.length); - for (i = tempDeck.length - 1; i > 0; i--) { - id = Math.floor(Math.random() * (i + 1)); - //shuffledPile = tempDeck[i]; - //tempDeck[i] = tempDeck[id]; - //tempDeck[id] = shuffledPile; - - // Change the position within the deck - listPosition[tempDeck[id]] = i; + console.log(getCurrentPositionAndLength('deck', playerId)[1]); + // For each item in the actual deck, set the listPosition to the random number from tempDeck + let items = board.ECSLoop('deck', playerId, null, null); + for(let item = 0; item < items.length; item++){ + let itemKey = items[item]; + console.log('ITEM KEY: '+itemKey); + console.log('OLD LIST POSITION: '+listPosition[itemKey]); + + listPosition[itemKey] = tempDeck[item]; + + console.log('NEW LIST POSITION: '+listPosition[itemKey]); } + console.log(getCurrentPositionAndLength('deck', playerId)[1]); + } @@ -1179,8 +1181,8 @@ function getCurrentPositionAndLength(elementName, playerId){ if(listPosition[itemKey] >= highestListPosition){ highestListPosition = listPosition[itemKey]; - length++; } + length++; } From 70f4a362b161f8fa616554b76fd9e4196d2bb9d0 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 13 Oct 2024 18:35:02 +0100 Subject: [PATCH 29/41] Add 'Test ECS Loop' to frontend --- public/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/public/index.html b/public/index.html index d741199..0ae9165 100644 --- a/public/index.html +++ b/public/index.html @@ -17,6 +17,7 @@ + From 9fac1d3dcc2c3b448407a6e14732697faa2d5ac0 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 13 Oct 2024 20:30:26 +0100 Subject: [PATCH 30/41] Jimmied in manaCost stuff, but not 100% working --- public/board.js | 121 ++++++++++++++++++++++++++++++------------------ 1 file changed, 76 insertions(+), 45 deletions(-) diff --git a/public/board.js b/public/board.js index 51ff2a4..706be98 100644 --- a/public/board.js +++ b/public/board.js @@ -624,65 +624,96 @@ class Board{ // Loop probably not needed, but may be for eg. 'play X cards from top of deck' for(let play = 0; play < cardsToPlay; play++){ - // Check there's space on board TODO: change to locationTo - // TODO: Normalise this for all element/player combos - let elementLength = getCurrentPositionAndLength(toElement, toPlayer)[1]; - // TODO: Compare against the maxSize for the boardElement - // this is fine(ish) for now, as just using hand - if(elementLength >= maxHandSize){ - alert('Board full '+elementLength+'/'+maxHandSize); - return 0; + + // Check there's space on the board/mana zone/shield/etc + if(!this.hasSpaceInBoardElement(toElement, toPlayer)){ + alert('No space in element'); + return false; } - // When done remove false && - // TODO: Rewrite for ECS - // Mana cost required and mana tapping for playing a card from hand, etc - if(false && cardPlayed.cost > playerMana.length){ - alert('Not enough mana'); - return 0; + + let itemKey = this.getItemKey(fromElement, positionFrom); + console.log(itemKey); + console.log(positionFrom); + + switch(fromElement){ + case 'hand': + // Mana cost required and mana tapping for playing a card from hand, etc + // The player casting/summoning should pay, ofc + let canPayMana = this.canPayMana(itemKey, fromPlayer) + if(canPayMana !== true){ + alert(canPayMana); + return false; + }else{ + // Tap mana and play TODO: TEMP SOLUTION + // TODO: May want to make this recursive, it's better and less bulky + // but still lots of dupe code + let items = this.ECSLoop('mana', fromPlayer, null, null); + for(let item = 0; item < items.length; item++){ + let mana = items[item]; + // For now just tapping the first untapped mana + // TODO: Tap mana of correct colour (also allow player to select in fut) + if(!this.isTapped(mana) && cardData[mana].colour == cardData[itemKey].colour){ + this.tapCard(mana); + }else{ + return false; + } + } + } } // Move from player0, position 0 (top) of deck, to hand, to pos(null/auto) for toPlayer this.addFromBoardElement(fromPlayer, positionFrom, fromElement, toElement, null, toPlayer); } + this.drawBoard(); + } - // Needs doing for playing cards from hand - if(false){ - let manaUsed = []; + getItemKey(boardElementId, listPositionId){ + let itemKey = this.ECSLoop(boardElementId, null, null, listPositionId); + if(itemKey.length < 1){ + alert('Could not find key'); + return false; + } + if(itemKey.length > 1){ + alert('Found more than one key'); + return false + } + // Return first index of array, aka the itemKey + return itemKey[0]; + } + + hasSpaceInBoardElement(toElement, toPlayer){ - if(cardPlayed.cost > playerMana.length){ - alert('Not enough mana'); - return 0; - }else{ - let canPlay = false; - let needsMana = 1; - let usedMana = 0; - playerMana.forEach(function(manaCard, key){ - if(cardPlayed.colour == manaCard.colour && manaCard.tapped == false && needsMana > usedMana){ - console.log(manaCard); - // Needs changing for multiple colour usage - // 2 red, 1 red + 1 blue, etc. - // Currently only gets one mana of the cards colour - manaUsed.push(key); - usedMana++; - canPlay = true; - } - }); + let elementLength = getCurrentPositionAndLength(toElement, toPlayer)[1]; - if(!canPlay){ - alert('Mana conditions not met, right click hand unit to play as mana'); - return 0; - } + if(elementLength >= maxHandSize){ + alert('Board full '+elementLength+'/'+maxHandSize); + return false; + } + return true; + } + canPayMana(itemToPlay, playerId){ + // Check player has enough mana + if(this.ECSLoop('mana', playerId, null, null).length < cardData[itemToPlay].cost){ + return 'Not enough mana'; } - // Tap mana to be used - manaUsed.forEach(function(cardKey, key){ - playerMana[cardKey].tapped = true; - }); - + // TODO: Check mana colours are available to play, then tap them + // TODO: Multicolours, and X of same colour checks + let manaUsed = []; + // For now, until adding colour, and other attributes to ECS modal + let manaRequired = cardData[itemToPlay].colour; + console.log(manaRequired); + let items = this.ECSLoop('mana', player[itemToPlay], null, null); + for(let item = 0; item < items.length; item++){ + let itemKey = items[item]; + if(cardData[itemKey].colour == manaRequired && !this.isTapped(itemKey)){ + manaUsed.push(itemKey); // This would be how I'd loop for X colour, or multi + return true; + } } - this.drawBoard(); + return 'Do not have correct mana requirements'; } inspectCard(cardToInspect){ From b2da688cf81efda53dc99f27d0e4078df1626c18 Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 14 Oct 2024 14:30:08 +0100 Subject: [PATCH 31/41] Add realDeck element and remove clickables --- public/board.js | 228 +++++++++++++++++++++--------------------------- 1 file changed, 98 insertions(+), 130 deletions(-) diff --git a/public/board.js b/public/board.js index 706be98..1037faf 100644 --- a/public/board.js +++ b/public/board.js @@ -8,13 +8,10 @@ const cardHeight = 120; const cards = new Image(); const back = new Image(); -// TODO: Remove once decks are migrated to ECS -let clickableItems = []; - // Counters to keep track of players, and boardElements, may be changed in future // But once game starts, will be const anyway, so shouldn't need passing let players = 2; // Player, Opponent for now, but will be up to 6 players for 5v1 boss raids? -let elements = ['deck','board','hand','mana','shield', 'grave']; +let elements = ['realDeck', 'deck','board','hand','mana','shield', 'grave']; let elementsSizes = {}; // TODO: May need to have the base XY WH of board, hand, etc. stored for loop draw // Array of items, the 'Entity Manager' as such let item = []; @@ -70,8 +67,6 @@ class Board{ // Room Name ctx.fillText(name, 0, 10); - this.drawDecks(); - this.drawPlayerNames('Nathan', 'Evil Nathan'); this.drawCardsECS(); // Atop most everything atm for testing @@ -158,10 +153,14 @@ class Board{ if(cardStatus[itemKey] == 'attacking'){border = '#C92D22';} // Set the card 'cardboard' colour based on the card colour type - let colourId = cardData[itemKey].colour; let fill = null; - if(colourId == 0){ fill = '#EEE'; } - else if(colourId == 1){ fill = '#0033EE'; } + if(boardElement[itemKey] != 'realDeck'){ // TODO: Change these to isset checks instead... + let colourId = cardData[itemKey].colour; + if(colourId == 0){ fill = '#EEE'; } + else if(colourId == 1){ fill = '#0033EE'; } + }else{ + fill = '#B0B0B0'; + } let name = itemKey; // Not needed really anymore, but keeping for now let positionX = position[itemKey][0]; @@ -181,9 +180,36 @@ class Board{ }); shape.draw(); - this.printCardImage(itemKey); + if(boardElement[itemKey] != 'realDeck'){ // TODO: isset, or differ between types + this.printCardImage(itemKey); + this.printCardDetails(itemKey); + }else{ + // TODO: For realDeck only atm, also janked in. Seperate this... + let counterx= positionX; + let countery= positionY; + let counterwidth= cardWidth*.375; + let counterheight= cardHeight*.375; + + // TODO: Center in the circle + let deckLength = getCurrentPositionAndLength('deck', player[itemKey])[1]; + let textx=positionX - (ctx.measureText(deckLength).width/2); + let texty=positionY + (ctx.measureText(deckLength).width/2); + // Draw circle for deck count to sit in + let deckCounterSprite = new Shape({ + shape: 'circle', + name: 'deckCountererer', + x: counterx, + y: countery, + width: counterwidth, + height: counterheight, + fillStyle: '#DCDCDC' + }); + deckCounterSprite.draw(); - this.printCardDetails(itemKey); + // Draw deck count text + ctx.fillStyle = '#000'; + ctx.fillText(deckLength, textx, texty); + } } @@ -344,101 +370,6 @@ class Board{ ctx.font = "10pt Arial"; } - drawDecks(){ - // Draw all decks belonging to players (currently 2, could be 3-5 in future, for PvE raids) - // TODO: Probably add this as an item of boardElement 'realDeck', as 'deck' is cards in deck - // actually, maybe change current 'deck' to 'inDeck', reads better - let name = null; - let countername = null; - let x = null; - let counterx = null; - let y = null; - let countery = null; - let width = null; - let counterwidth = null; - let height = null; - let counterheight = null; - let fill = null; - let counterfill = '#FFF'; - let textx = null; - let texty = null; - let deckLength = 0; - - for(let playerId = 0; playerId < players; playerId++){ - if(playerId == 0){ - // Deck - name= 'deck'; - x= canvas.width-cardWidth*1.5-40; - y= canvas.height-cardHeight*1.5-60; - width= cardWidth*1.5; - height= cardHeight*1.5; - fill= "#0000FF"; - - countername= 'deckCounter'; - counterx= canvas.width-cardWidth*.6; - countery= canvas.height-cardHeight*.6; - counterwidth= cardWidth*.375; - counterheight= cardHeight*.375; - - // TODO: Center in the circle - deckLength = getCurrentPositionAndLength('deck', 0)[1]; - textx = canvas.width-cardWidth*.6 - (ctx.measureText(deckLength).width) + 7; - texty = canvas.height-cardHeight*.6 + 5; - } - if(playerId == 1){ - // Opponent's Deck - name= 'deckOpponent'; - x= 40; - y= 60; - width= cardWidth*1.5; - height= cardHeight*1.5; - fill= "#FF0000"; - - countername= 'deckCounterOpponent'; - counterx= cardWidth*1.5+(cardWidth*.375); - countery= cardHeight*1.5+(cardHeight*.375); - counterwidth= cardWidth*.375; - counterheight= cardHeight*.375; - counterfill= "#FFF"; - - deckLength = getCurrentPositionAndLength('deck', 1)[1]; - textx=cardWidth*1.5 + (ctx.measureText(deckLength).width) + 10; - texty=cardHeight*1.9; - - } - - // Actually draw the decks base on the size/position, etc. - clickableItems[name+'Sprite'] = new Shape({ - name: name, - x: x, - y: y, - width: width, - height: height, - fillStyle: fill - }); - //ctx.fillRect(canvas.width-cardWidth/2-60, canvas.height/2-cardHeight/4, cardWidth/2, cardHeight/2); - clickableItems[name+'Sprite'].draw(); - - // Draw circle for deck count to sit in - let deckCounterSprite = new Shape({ - shape: 'circle', - name: countername, - x: counterx, - y: countery, - width: counterwidth, - height: counterheight, - fillStyle: counterfill - }); - deckCounterSprite.draw(); - - // Draw deck count text - // TODO: Center in the circle - ctx.fillStyle = '#000'; - ctx.fillText(deckLength, textx, texty); - } - - } - // boardElement, cardData?, position?, size?, cardStatus, player, listPosition ECSLoop(boardElementId = null, playerId = null, cardStatusId = null, listPositionId = null){ // So, the intent here is to normalise my nested loop I keep duping (parts of) @@ -909,6 +840,7 @@ class Board{ let board = new Board; // TODO: TEMP!! Replace soon +createDeck(); createDeckList(playerDeck, deckCount, 0); createDeckList(opponentDeck, deckCountOpponent, 1); @@ -983,12 +915,14 @@ canvas.addEventListener('click', function(event) { // Will be the new way // TODO:Maybe write this into a function? If XY WH is hit return true, and the itemKey // then it can be re-used in contextclick, hover, etc without rewrite - //console.log('X: '+x+' Y: '+y); + console.log('X: '+x+' Y: '+y); // TODO: Normalise this too for(let itemKey = 0; itemKey < item.length; itemKey++){ - if(elements[itemKey] == 'deck'){ + if(boardElement[itemKey] == 'deck'){ continue; + }else{ + //printECSData([itemKey]); } // Check the item has a size and position @@ -1007,6 +941,9 @@ canvas.addEventListener('click', function(event) { // Check item location, and trigger events based on it // TODO: Change inEvent locations, and checks elsewhere? // TODO: Make existing mechanics ECSey + case 'realDeck': + board.drawACard(playerId, 1); + break; case 'board': // player/opponentBoard not seperated, as want to have // each player able to have effects, etc. to make others attack @@ -1059,21 +996,6 @@ canvas.addEventListener('click', function(event) { } } - // Decks kept as-is for now - // TODO: boardElement realDeck, or smth and add these to the loop - // # PLAYER DECK - clickable = clickableItems['deckSprite']; - if(clickableCheck(x,y,clickable) && !inEvent){ - board.drawACard(0); - } - - // TODO: - // # OPPONENT DECK - clickable = clickableItems['deckOpponentSprite']; - if(clickableCheck(x,y,clickable) && !inEvent){ - board.drawACard(1); - } - }, false); function clickableCheck(x,y,clickable=false,itemKey=false){ @@ -1112,12 +1034,29 @@ function clickableCheck(x,y,clickable=false,itemKey=false){ } +function createDeck(){ + // Create a 'realDeck' element for each player + for(let i = 0; i < players; i++){ + item.push(itemCount); + boardElement[itemCount] = 'realDeck'; + player[itemCount] = i; + // TODO: Added these in to prevent error + // In future want to remove, and add isset checks for non-used data + cardStatus[itemCount] = null; + listPosition[itemCount] = null; + itemCount++; + } + + console.log(item.length); // createDeckList will need to continue from here, not 0 +} // TEMP: Create a deck of X different cards that can be drawn/played // for UI development, will be done on server and not shown to clients // TODO: Randomly create a deck from objects stored in file (for now) then DB // 3 of each card max, and likely one colour too for time being function createDeckList(deck, deckCount, playerId){ - for(let i = 0; i < deckCount; i++){ + let i = item.length; // Continue from the last item, don't overwrite + deckCount = deckCount + i; + for(i; i < deckCount; i++){ // Randomise colour let colour = Math.floor(Math.random() * 2); let effect = Math.floor(Math.random() * 5); @@ -1168,12 +1107,12 @@ function shuffleDeck(playerId){ let items = board.ECSLoop('deck', playerId, null, null); for(let item = 0; item < items.length; item++){ let itemKey = items[item]; - console.log('ITEM KEY: '+itemKey); - console.log('OLD LIST POSITION: '+listPosition[itemKey]); + //console.log('ITEM KEY: '+itemKey); + //console.log('OLD LIST POSITION: '+listPosition[itemKey]); listPosition[itemKey] = tempDeck[item]; - console.log('NEW LIST POSITION: '+listPosition[itemKey]); + //console.log('NEW LIST POSITION: '+listPosition[itemKey]); } console.log(getCurrentPositionAndLength('deck', playerId)[1]); @@ -1245,6 +1184,20 @@ function calculateItemSizePosition(itemKey){ let i = listPosition[itemKey]; //console.log('cardName: '+cardData[itemKey].name+' listPosition/i: '+i); + if(itemPlayer == 1 && itemElement == 'realDeck'){ + positionX = 40; + positionY = 60; + width = cardWidth*1.5; + height = cardHeight*1.5; + + } + if(itemPlayer == 0 && itemElement == 'realDeck'){ + positionX = canvas.width-cardWidth*1.5-40; + positionY = canvas.height-cardHeight*1.5-60; + width = cardWidth*1.5; + height = cardHeight*1.5; + } + if(itemPlayer == 1 && itemElement == 'board'){ positionX = canvas.width/2 - (cardWidth * (itemListLength - i) - (cardMargin * i)); positionY = cardHeight + 30; @@ -1336,12 +1289,27 @@ function calculateItemSizePosition(itemKey){ function ECSLoopTest(){ // boardElement, player, cardStatus, listPosition // TODO: ?cardData?, position?, size? - let boardElementId = 'board'; - let playerId = 0; + let boardElementId = 'realDeck'; + let playerId = null; let cardStatusId = null; let listPositionId = null; let items = board.ECSLoop(boardElementId, playerId, cardStatusId, listPositionId); - console.log('Items in boardElement: '+boardElementId+' player: '+playerId+' cardStatus: '+cardStatusId+' listPosition: '+listPositionId); + console.log(items); + printECSData(items); +} +function printECSData(items){ + for(let item = 0; item < items.length; item++){ + let itemKey = items[item]; + console.log( + 'boardElement: '+boardElement[itemKey]+"\n"+ + 'cardData: '+cardData[itemKey]+"\n"+ + 'position: '+position[itemKey]+"\n"+ + 'size: '+size[itemKey]+"\n"+ + 'cardStatus: '+cardStatus[itemKey]+"\n"+ + 'player: '+player[itemKey]+"\n"+ + 'listPosition: '+listPosition[itemKey] + ); + } } From 79bd2da8452d7ac997a9f83f56047ec3032a84ff Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 14 Oct 2024 15:49:26 +0100 Subject: [PATCH 32/41] Add faux deckDB/array to add cards/decklists --- public/board.js | 81 +++++++++++++++++++++++++++-------------------- public/cards.js | 21 ++++++++++++ public/index.html | 4 +++ 3 files changed, 71 insertions(+), 35 deletions(-) create mode 100644 public/cards.js diff --git a/public/board.js b/public/board.js index 1037faf..568b222 100644 --- a/public/board.js +++ b/public/board.js @@ -158,6 +158,7 @@ class Board{ let colourId = cardData[itemKey].colour; if(colourId == 0){ fill = '#EEE'; } else if(colourId == 1){ fill = '#0033EE'; } + else if(colourId == 2){ fill = '#ED344A'; } }else{ fill = '#B0B0B0'; } @@ -541,7 +542,7 @@ class Board{ alert('Hand full '+elementLength+'/'+maxHandSize); return 0; } - this.addFromBoardElement(playerId, 0, 'deck', 'hand', null, null); + this.addFromBoardElement(playerId, 1, 'deck', 'hand', null, null); } } @@ -841,12 +842,12 @@ let board = new Board; // TODO: TEMP!! Replace soon createDeck(); -createDeckList(playerDeck, deckCount, 0); -createDeckList(opponentDeck, deckCountOpponent, 1); +//createDeckList(playerDeck, deckCount, 0); +//createDeckList(opponentDeck, deckCountOpponent, 1); // Play 4 shield from top (0) of each players deck for(let currentPlayer = 0; currentPlayer <= players-1; currentPlayer++){ - board.playShield(0, 'deck', currentPlayer, 4); + board.playShield(1, 'deck', currentPlayer, 4); } board.drawBoard(true); @@ -1047,43 +1048,40 @@ function createDeck(){ itemCount++; } - console.log(item.length); // createDeckList will need to continue from here, not 0 + // Loop again and create the deckLists + for(let i = 0; i < players; i++){ + createDeckList(i); + } + } -// TEMP: Create a deck of X different cards that can be drawn/played -// for UI development, will be done on server and not shown to clients -// TODO: Randomly create a deck from objects stored in file (for now) then DB -// 3 of each card max, and likely one colour too for time being -function createDeckList(deck, deckCount, playerId){ - let i = item.length; // Continue from the last item, don't overwrite - deckCount = deckCount + i; - for(i; i < deckCount; i++){ - // Randomise colour - let colour = Math.floor(Math.random() * 2); - let effect = Math.floor(Math.random() * 5); - if(effect == 0){ effect = 'effect here'; } else{ effect = null } - +// TODO: USE DATABASE FOR THIS!!! +function createDeckList(playerId){ + // TODO:Create the deckList by loading the deckDB + // For now pulling from a deckList array that uses a cardArray + let deckList = null; + if(playerId == 0){ deckList = deckListPlayer; } + if(playerId == 1){ deckList = deckListOpponent; } + + for(let deckItem = 0; deckItem < deckList.length; deckItem++){ + // Create new item for ECS item.push(itemCount); + // Set card data for new item + // Use the ID from the deckList of player, and return the card of that ID from cardList/DB + cardData[itemCount] = cardArray[deckList[deckItem]]; + // Set to base position of 'deck' boardElement[itemCount] = 'deck'; - cardData[itemCount] = { - 'name':'CardName '+(i+1) - , 'cost':1 - , 'atk':1 - , 'def':1 - , 'rarity': 'common' - , 'effect':effect - , 'type':'human' - , 'colour':colour - , 'tapped':false - }; + // Set Attack, ManaCost, ManaColours TODO: When these are implemented seperately + + // Set the player player[itemCount] = playerId; - listPosition[itemCount] = i; - // Previous iteration, kept to prevent errors for now - deck.push(cardData[itemCount]); + // Set the position in the deck (as was added), will be shuffled on game start + listPosition[itemCount] = deckItem+1; + // Increment the itemCount to prevent overwriting stuff itemCount++; } + let cardsInDeck = board.ECSLoop(null, playerId); - // Shuffle the deck straight away after generating/loading it in shuffleDeck(playerId); } @@ -1102,7 +1100,6 @@ function shuffleDeck(playerId){ [ tempDeck[i], tempDeck[shuffle] ] = [ tempDeck[shuffle], tempDeck[i] ]; } - console.log(getCurrentPositionAndLength('deck', playerId)[1]); // For each item in the actual deck, set the listPosition to the random number from tempDeck let items = board.ECSLoop('deck', playerId, null, null); for(let item = 0; item < items.length; item++){ @@ -1114,7 +1111,6 @@ function shuffleDeck(playerId){ //console.log('NEW LIST POSITION: '+listPosition[itemKey]); } - console.log(getCurrentPositionAndLength('deck', playerId)[1]); } @@ -1312,4 +1308,19 @@ function printECSData(items){ ); } } +function echoCards(){ + console.log(cardArray); +} +function echoCardsInDeck(playerId){ + // Get all the cards that belong to player + let cardsInDeck = board.ECSLoop(null, playerId); + let deckList = []; + for(let i = 0; i < cardsInDeck.length; i++){ + // If it's a card TODO: Change this to check 'card' from some ECS element + if(cardData[i] !== null && cardData[i] !== undefined){ + deckList.push(cardData[i]); + } + } + console.log(deckList); +} diff --git a/public/cards.js b/public/cards.js new file mode 100644 index 0000000..f6f6092 --- /dev/null +++ b/public/cards.js @@ -0,0 +1,21 @@ +// 0,1,2 = white,blue,red (for now) +// TODO: Use a DB in future, this is just for testing +let cardArray = +[ + { id: 1, name: 'Red1', colour: 2, cost: 1, type: 'Goblin', atk: 500, rarity: 'common', effect:'[[Sneak]] 500'}, + { id: 2, name: 'Red2', colour: 2, cost: 1, type: 'Goblin', atk: 1500, rarity: 'common', effect:'Cannot attack direct'}, + { id: 3, name: 'Red3', colour: 2, cost: 2, type: 'Goblin', atk: 1000, rarity: 'common', effect:'[[DEATH]] deal 1500 extra to killer'}, + { id: 4, name: 'Red4', colour: 2, cost: 2, type: 'Goblin', atk: 2000, rarity: 'common', effect:null}, + { id: 5, name: 'White1', colour: 0, cost: 1, type: 'Weapon', atk: 500, rarity: 'common', effect:'[[Equip]]'}, + { id: 6, name: 'White2', colour: 0, cost: 2, type: 'Human', atk: 1500, rarity: 'common', effect:null}, + { id: 7, name: 'White3', colour: 0, cost: 2, type: 'Human', atk: 2000, rarity: 'common', effect:'[[TAUNT]]'}, + { id: 8, name: 'White5', colour: 0, cost: 2, type: 'Human', atk: 1500, rarity: 'common', effect:'[[REACH]]'}, + { id: 9, name: 'Blue1', colour: 1, cost: 2, type: 'Spirit', atk: 1000, rarity: 'common', effect:null}, + { id: 10, name: 'Blue3', colour: 1, cost: 2, type: 'Spirit', atk: 1000, rarity: 'common', effect:'[[DRAW]] 1'}, + { id: 11, name: 'Blue4', colour: 1, cost: 2, type: 'Spirit', atk: 1500, rarity: 'common', effect:null}, + { id: 12, name: 'Blue5', colour: 1, cost: 3, type: 'Spirit', atk: 2500, rarity: 'common', effect:'[[FLIGHT]]'} +] + +let deckListPlayer = [5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10]; +let deckListOpponent = [1,1,1,1,2,2,3,3,4,4,7,7,7,7,5,5,5,3,3,8,8]; + diff --git a/public/index.html b/public/index.html index 0ae9165..d28ac6c 100644 --- a/public/index.html +++ b/public/index.html @@ -18,8 +18,12 @@ + + + + From 515067936e939a8558dbccdce2626d72615df78e Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 14 Oct 2024 17:51:21 +0100 Subject: [PATCH 33/41] Prevent multi-mana taps when only one should --- public/board.js | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/public/board.js b/public/board.js index 568b222..8d2bfcd 100644 --- a/public/board.js +++ b/public/board.js @@ -486,8 +486,15 @@ class Board{ playerTo = playerFrom; } + // Check if there's more than 1 thing add that position (something's gone wrong somewhere) + let items = this.ECSLoop(elementFrom, playerFrom, null, fromPosition); + if(board.ECSLoop(elementFrom, playerFrom, null, fromPosition).length > 1){ + alert('ERROR: There are more than 1 card being added'); + } + // First (and only) item returned is the key thins should be done with - let itemKey = this.ECSLoop(elementFrom, playerFrom, null, fromPosition)[0]; + let itemKey = items[0]; + if(listPosition[itemKey] == fromPosition){ // Check if a toPostion supplied if(toPosition == null){ @@ -571,7 +578,7 @@ class Board{ case 'hand': // Mana cost required and mana tapping for playing a card from hand, etc // The player casting/summoning should pay, ofc - let canPayMana = this.canPayMana(itemKey, fromPlayer) + let canPayMana = this.canPayMana(itemKey, fromPlayer); if(canPayMana !== true){ alert(canPayMana); return false; @@ -586,8 +593,9 @@ class Board{ // TODO: Tap mana of correct colour (also allow player to select in fut) if(!this.isTapped(mana) && cardData[mana].colour == cardData[itemKey].colour){ this.tapCard(mana); + break; // Temp TODO: Tap each mana needed until manacost/colours are met, also TODO: allow user to target own mana OR use non-multitypes first (not implemented yet) }else{ - return false; + continue; } } } @@ -634,13 +642,14 @@ class Board{ // TODO: Multicolours, and X of same colour checks let manaUsed = []; // For now, until adding colour, and other attributes to ECS modal - let manaRequired = cardData[itemToPlay].colour; - console.log(manaRequired); + let manaColourRequired = cardData[itemToPlay].colour; + console.log(manaColourRequired); let items = this.ECSLoop('mana', player[itemToPlay], null, null); for(let item = 0; item < items.length; item++){ let itemKey = items[item]; - if(cardData[itemKey].colour == manaRequired && !this.isTapped(itemKey)){ + if(cardData[itemKey].colour == manaColourRequired && !this.isTapped(itemKey)){ manaUsed.push(itemKey); // This would be how I'd loop for X colour, or multi + console.log(manaUsed); return true; } } @@ -771,11 +780,12 @@ class Board{ } } - playMana(fromPosition, fromElement, cardsToPlay = 1){ + playMana(fromPosition, fromElement, fromPlayer, cardsToPlay = 1){ // Move from player0, fromPosition of hand (for now), to mana // TODO: FOR ALL addFromBoardElements, if 'fromPosition' not passed get the // fromPosition and boardElementFrom from the itemId (will need to change to pass this) - this.addFromBoardElement(0, fromPosition, fromElement, 'mana', null, null); + console.log('playMana('+fromPosition+','+fromElement+','+cardsToPlay+')'); + this.addFromBoardElement(fromPlayer, fromPosition, fromElement, 'mana', null, null); } // HELPER METHODS, to simplify code-base for me in the future @@ -860,6 +870,8 @@ canvas.addEventListener('contextmenu', function(event) { var x = event.pageX - canvasLeft, y = event.pageY - canvasTop; + console.log('RIGHT CLICK X: '+x+' Y: '+y); + for(let itemKey = 0; itemKey < item.length; itemKey++){ if(elements[itemKey] == 'deck'){ @@ -874,6 +886,9 @@ canvas.addEventListener('contextmenu', function(event) { // Only want to happen once (for now) // Maybe in future add to hand would trigger another event if there's an effect? + // Player the item belongs to, not who's doing the action + let playerId = player[itemKey]; + // Check the location of element switch(boardElement[itemKey]){ // Check item location, and trigger events based on it @@ -886,15 +901,17 @@ canvas.addEventListener('contextmenu', function(event) { if(inEvent && inEvent[0] == 'attack' && itemKey == inEvent[1]){ board.cancelAttackFor(itemKey); } - board.drawBoard(); break; case 'hand': // Can be played as mana (right click for now) // Play item from boardElement hand. To boardElement mana (explanitory) - board.playMana(listPosition[itemKey], 'hand'); - board.drawBoard(); + board.playMana(listPosition[itemKey], 'hand', playerId); + break; + default: break; } + board.drawBoard(); + return true; } } } @@ -916,7 +933,7 @@ canvas.addEventListener('click', function(event) { // Will be the new way // TODO:Maybe write this into a function? If XY WH is hit return true, and the itemKey // then it can be re-used in contextclick, hover, etc without rewrite - console.log('X: '+x+' Y: '+y); + console.log('LEFT CLICK X: '+x+' Y: '+y); // TODO: Normalise this too for(let itemKey = 0; itemKey < item.length; itemKey++){ @@ -991,8 +1008,11 @@ canvas.addEventListener('click', function(event) { board.makeAttack(itemKey); } break; + default: + break; } board.drawBoard(); + return true; } } } From 997ffae3c48b4f2b86eb471db129a0d99e866897 Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 14 Oct 2024 18:17:45 +0100 Subject: [PATCH 34/41] Add frontend console.log tool, renamed ECSLoop --- public/board.js | 55 ++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/public/board.js b/public/board.js index 8d2bfcd..ed89090 100644 --- a/public/board.js +++ b/public/board.js @@ -372,7 +372,7 @@ class Board{ } // boardElement, cardData?, position?, size?, cardStatus, player, listPosition - ECSLoop(boardElementId = null, playerId = null, cardStatusId = null, listPositionId = null){ + getItems(boardElementId = null, playerId = null, cardStatusId = null, listPositionId = null){ // So, the intent here is to normalise my nested loop I keep duping (parts of) // This will recieve each piece of content that can be stored in each ECS element // Then will loop each individually, setting a new array to be returned @@ -487,8 +487,8 @@ class Board{ } // Check if there's more than 1 thing add that position (something's gone wrong somewhere) - let items = this.ECSLoop(elementFrom, playerFrom, null, fromPosition); - if(board.ECSLoop(elementFrom, playerFrom, null, fromPosition).length > 1){ + let items = this.getItems(elementFrom, playerFrom, null, fromPosition); + if(board.getItems(elementFrom, playerFrom, null, fromPosition).length > 1){ alert('ERROR: There are more than 1 card being added'); } @@ -525,7 +525,7 @@ class Board{ // Loop the elementFrom, and move positions for anything after // item taken from position 34, 35..60 need to be moved down to 34..59 - let items = this.ECSLoop(elementFrom, playerFrom, null, null); + let items = this.getItems(elementFrom, playerFrom, null, null); for(let item = 0; item < items.length; item++){ let itemKey = items[item]; if(listPosition[itemKey] > fromPosition){ @@ -586,7 +586,7 @@ class Board{ // Tap mana and play TODO: TEMP SOLUTION // TODO: May want to make this recursive, it's better and less bulky // but still lots of dupe code - let items = this.ECSLoop('mana', fromPlayer, null, null); + let items = this.getItems('mana', fromPlayer, null, null); for(let item = 0; item < items.length; item++){ let mana = items[item]; // For now just tapping the first untapped mana @@ -609,7 +609,7 @@ class Board{ } getItemKey(boardElementId, listPositionId){ - let itemKey = this.ECSLoop(boardElementId, null, null, listPositionId); + let itemKey = this.getItems(boardElementId, null, null, listPositionId); if(itemKey.length < 1){ alert('Could not find key'); return false; @@ -634,7 +634,7 @@ class Board{ } canPayMana(itemToPlay, playerId){ // Check player has enough mana - if(this.ECSLoop('mana', playerId, null, null).length < cardData[itemToPlay].cost){ + if(this.getItems('mana', playerId, null, null).length < cardData[itemToPlay].cost){ return 'Not enough mana'; } @@ -644,7 +644,7 @@ class Board{ // For now, until adding colour, and other attributes to ECS modal let manaColourRequired = cardData[itemToPlay].colour; console.log(manaColourRequired); - let items = this.ECSLoop('mana', player[itemToPlay], null, null); + let items = this.getItems('mana', player[itemToPlay], null, null); for(let item = 0; item < items.length; item++){ let itemKey = items[item]; if(cardData[itemKey].colour == manaColourRequired && !this.isTapped(itemKey)){ @@ -804,7 +804,7 @@ class Board{ } // Get all shields, that belong to the player whose shield was targetted. // Check if they're all tapped before destroying the target - let items = this.ECSLoop('shield', player[itemKey], null, null); + let items = this.getItems('shield', player[itemKey], null, null); for(let item = 0; item < items.length; item++){ let itemKey = items[item]; // If ANY of their shields are untapped, you can't destroy target @@ -1100,7 +1100,7 @@ function createDeckList(playerId){ // Increment the itemCount to prevent overwriting stuff itemCount++; } - let cardsInDeck = board.ECSLoop(null, playerId); + let cardsInDeck = board.getItems(null, playerId); shuffleDeck(playerId); } @@ -1121,7 +1121,7 @@ function shuffleDeck(playerId){ } // For each item in the actual deck, set the listPosition to the random number from tempDeck - let items = board.ECSLoop('deck', playerId, null, null); + let items = board.getItems('deck', playerId, null, null); for(let item = 0; item < items.length; item++){ let itemKey = items[item]; //console.log('ITEM KEY: '+itemKey); @@ -1136,7 +1136,7 @@ function shuffleDeck(playerId){ } function untapZone(elementFrom, playerFrom){ - let items = board.ECSLoop(elementFrom, playerFrom, null, null); + let items = board.getItems(elementFrom, playerFrom, null, null); for(let item = 0; item < items.length; item++){ let itemKey = items[item]; if(board.isTapped(itemKey)){ board.untapCard(itemKey); } @@ -1161,7 +1161,7 @@ function getCurrentPositionAndLength(elementName, playerId){ let highestListPosition = 0; let length = 0; - let items = board.ECSLoop(elementName, playerId, null, null); + let items = board.getItems(elementName, playerId, null, null); for(let item = 0; item < items.length; item++){ let itemKey = items[item]; @@ -1302,17 +1302,24 @@ function calculateItemSizePosition(itemKey){ position[itemKey] = [positionX,positionY]; } -function ECSLoopTest(){ - // boardElement, player, cardStatus, listPosition - // TODO: ?cardData?, position?, size? - let boardElementId = 'realDeck'; - let playerId = null; - let cardStatusId = null; - let listPositionId = null; - let items = board.ECSLoop(boardElementId, playerId, cardStatusId, listPositionId); - - console.log(items); + +// For checking data without needing to change the codebase with logs +function getItemsAndPrintFrontEnd(){ + let boardElementId = document.getElementById("boardElementId").value; + if(boardElementId == ""){ boardElementId = null; } + let playerId = document.getElementById("playerId").value; + if(playerId == ""){ playerId = null; } + let cardStatusId = document.getElementById("cardStatusId").value; + if(cardStatusId == ""){ cardStatusId = null; } + let listPositionId = document.getElementById("listPositionId").value; + if(listPositionId == ""){ listPositionId = null; } + getItemsAndPrint(boardElementId, playerId, cardStatusId, listPositionId); +} +function getItemsAndPrint(boardElementId = null, playerId = null, cardStatusId = null, listPositionId = null){ + let items = board.getItems(boardElementId, playerId, cardStatusId, listPositionId); + console.log('----- Items -----'); printECSData(items); + console.log('Items array length: '+items.length); } function printECSData(items){ for(let item = 0; item < items.length; item++){ @@ -1333,7 +1340,7 @@ function echoCards(){ } function echoCardsInDeck(playerId){ // Get all the cards that belong to player - let cardsInDeck = board.ECSLoop(null, playerId); + let cardsInDeck = board.getItems(null, playerId); let deckList = []; for(let i = 0; i < cardsInDeck.length; i++){ // If it's a card TODO: Change this to check 'card' from some ECS element From 36f63ef35475dc9516dce491ecff12690489205a Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 14 Oct 2024 18:20:16 +0100 Subject: [PATCH 35/41] FIX FOR LAST COMMIT Forgot to add the index.html including change, and addition... --- public/index.html | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/public/index.html b/public/index.html index d28ac6c..8fe222c 100644 --- a/public/index.html +++ b/public/index.html @@ -22,6 +22,36 @@ +
+
+ + + + + + + + + +
+ From 64a6a3ca854c560fe171547e0384be42aa7117e4 Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 14 Oct 2024 18:21:35 +0100 Subject: [PATCH 36/41] Remove redundant ECSLoopTest from frontend --- public/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/public/index.html b/public/index.html index 8fe222c..528d4f9 100644 --- a/public/index.html +++ b/public/index.html @@ -17,7 +17,6 @@ - From b86e41c01031523decc610392ea0dd3894a70ab8 Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 14 Oct 2024 19:02:42 +0100 Subject: [PATCH 37/41] Fix error when playing card from hand When opponent has hand in same position. Added playerId to check --- public/board.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/board.js b/public/board.js index ed89090..3f474cb 100644 --- a/public/board.js +++ b/public/board.js @@ -570,7 +570,7 @@ class Board{ return false; } - let itemKey = this.getItemKey(fromElement, positionFrom); + let itemKey = this.getItemKey(fromElement, positionFrom, fromPlayer); console.log(itemKey); console.log(positionFrom); @@ -608,8 +608,8 @@ class Board{ this.drawBoard(); } - getItemKey(boardElementId, listPositionId){ - let itemKey = this.getItems(boardElementId, null, null, listPositionId); + getItemKey(boardElementId, listPositionId, playerFrom){ + let itemKey = this.getItems(boardElementId, playerFrom, null, listPositionId); if(itemKey.length < 1){ alert('Could not find key'); return false; From afee6247fc99a32f18528aed6097947615e28693 Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 14 Oct 2024 20:09:50 +0100 Subject: [PATCH 38/41] Add itemdata/cardData filter to frontend debug --- public/board.js | 26 +++++++++++++++++++++----- public/index.html | 5 +++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/public/board.js b/public/board.js index 3f474cb..3051e48 100644 --- a/public/board.js +++ b/public/board.js @@ -1087,7 +1087,8 @@ function createDeckList(playerId){ item.push(itemCount); // Set card data for new item // Use the ID from the deckList of player, and return the card of that ID from cardList/DB - cardData[itemCount] = cardArray[deckList[deckItem]]; + // ID 1 was adding id 0 as array index. Changed to +1 for now (will correct in DB form) + cardData[itemCount] = cardArray[deckList[deckItem]+1]; // Set to base position of 'deck' boardElement[itemCount] = 'deck'; // Set Attack, ManaCost, ManaColours TODO: When these are implemented seperately @@ -1313,12 +1314,18 @@ function getItemsAndPrintFrontEnd(){ if(cardStatusId == ""){ cardStatusId = null; } let listPositionId = document.getElementById("listPositionId").value; if(listPositionId == ""){ listPositionId = null; } - getItemsAndPrint(boardElementId, playerId, cardStatusId, listPositionId); + let itemOrCard = document.getElementById("itemOrCardData").value; + getItemsAndPrint(boardElementId, playerId, cardStatusId, listPositionId, itemOrCard); } -function getItemsAndPrint(boardElementId = null, playerId = null, cardStatusId = null, listPositionId = null){ +function getItemsAndPrint(boardElementId = null, playerId = null, cardStatusId = null, listPositionId = null, itemOrCard = 'item'){ let items = board.getItems(boardElementId, playerId, cardStatusId, listPositionId); - console.log('----- Items -----'); - printECSData(items); + if(itemOrCard == 'card'){ + console.log('----- CardData -----'); + printCardData(items); + }else{ + console.log('----- ItemData -----'); + printECSData(items); + } console.log('Items array length: '+items.length); } function printECSData(items){ @@ -1335,6 +1342,15 @@ function printECSData(items){ ); } } +function printCardData(items){ + let cardArray = []; + for(let item = 0; item < items.length; item++){ + let itemKey = items[item]; + cardArray.push(cardData[itemKey]); + } + console.log(cardArray); + +} function echoCards(){ console.log(cardArray); } diff --git a/public/index.html b/public/index.html index 528d4f9..8cc583f 100644 --- a/public/index.html +++ b/public/index.html @@ -49,6 +49,11 @@ + + From 0ccb65b1a31ac3a4e01b31c3d150ba3e7aeff77d Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 14 Oct 2024 20:56:02 +0100 Subject: [PATCH 39/41] Fix wrong cards added to deck --- public/board.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/public/board.js b/public/board.js index 3051e48..c4d90d5 100644 --- a/public/board.js +++ b/public/board.js @@ -1087,8 +1087,9 @@ function createDeckList(playerId){ item.push(itemCount); // Set card data for new item // Use the ID from the deckList of player, and return the card of that ID from cardList/DB - // ID 1 was adding id 0 as array index. Changed to +1 for now (will correct in DB form) - cardData[itemCount] = cardArray[deckList[deckItem]+1]; + // For now, needs to be -1, as ID1 in decklist refers to ID 1 of carlist which is INDEX 0 + // TODO: Make it use the cardList ID, not the index + cardData[itemCount] = cardArray[deckList[deckItem]-1]; // Set to base position of 'deck' boardElement[itemCount] = 'deck'; // Set Attack, ManaCost, ManaColours TODO: When these are implemented seperately From 8296074cb506e3e85620448a2cf466eb14c822b2 Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 14 Oct 2024 21:01:02 +0100 Subject: [PATCH 40/41] Wrap inEvent logic around each eventHandler case --- public/board.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/public/board.js b/public/board.js index c4d90d5..7ae31bb 100644 --- a/public/board.js +++ b/public/board.js @@ -905,7 +905,9 @@ canvas.addEventListener('contextmenu', function(event) { case 'hand': // Can be played as mana (right click for now) // Play item from boardElement hand. To boardElement mana (explanitory) - board.playMana(listPosition[itemKey], 'hand', playerId); + if(!inEvent){ + board.playMana(listPosition[itemKey], 'hand', playerId); + } break; default: break; @@ -960,7 +962,9 @@ canvas.addEventListener('click', function(event) { // TODO: Change inEvent locations, and checks elsewhere? // TODO: Make existing mechanics ECSey case 'realDeck': - board.drawACard(playerId, 1); + if(!inEvent){ + board.drawACard(playerId, 1); + } break; case 'board': // player/opponentBoard not seperated, as want to have @@ -999,7 +1003,9 @@ canvas.addEventListener('click', function(event) { break; case 'hand': // TODO: Ensure it can be played - board.playCardToBoard(listPosition[itemKey], 'hand', 'board', playerId, playerId, 1); + if(!inEvent){ + board.playCardToBoard(listPosition[itemKey], 'hand', 'board', playerId, playerId, 1); + } break; case 'shield': // If you have an attack, and click opponent shield, From 8d3f8b99d73854c265e36695165a1be8c16caf3d Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 14 Oct 2024 23:19:36 +0100 Subject: [PATCH 41/41] Simplifying code for future me + tidyup/removal P1 --- public/board.js | 427 +++++++++++++++++------------------------------- 1 file changed, 154 insertions(+), 273 deletions(-) diff --git a/public/board.js b/public/board.js index 7ae31bb..8a237f9 100644 --- a/public/board.js +++ b/public/board.js @@ -28,24 +28,14 @@ let player = {}; let listPosition = {}; let inEvent = null; -// TODO: Do something else ECSey, think most logic for this is about -let playerDeck = []; -let opponentDeck = []; -// TODO: Re-implement, then remove existing code -let playerMana = []; -let playerHand = []; - // To disable drawing each time something changes let drawEachEvent = true; // For disabling draw each time and only occuring where I want to test let yourPlayerId = 0; // To compare click events of your/opponents cards let viewingPlayerId = 0; // To show the board from your/opponent/teammates perspective, etc. without play permission -let deckCount = 35; -let deckCountOpponent = 35; - const maxHandSize = 4; const maxBoardSize = 3; -const maxShield = 4; +const maxShield = 2; // Gonna need lots of refactoring, and sorting class Board{ @@ -69,7 +59,7 @@ class Board{ this.drawPlayerNames('Nathan', 'Evil Nathan'); - this.drawCardsECS(); // Atop most everything atm for testing + this.drawItems(); // Atop most everything atm for testing if(this.checkGameWin() == true){ this.drawWin(); @@ -110,31 +100,24 @@ class Board{ } } - drawCardsECS(){ - // ALL NON DECK CARDS DO BE DRAWN IN SAME LOOP (ideally) + drawItems(){ // Loop all items for(let itemKey = 0; itemKey < item.length; itemKey++){ - - // Loop each element, and player + // Loop each element to draw (each have distinct locations, and draw logic) for(let elementCount in elements){ - // Don't draw deck TODO:/gy/void // TODO: Unless inspecting let element = elements[elementCount]; - if(element == 'deck'){ + if(element == 'deck' || element == 'grave'){ continue; } // Draw Elements - // Loop each item left, and draw if element is currently looped. board,mana,etc. + // Loop each item remaining, draw them if(itemKey in boardElement && boardElement[itemKey] == element){ - if(boardElement[itemKey] == 'board' && player[itemKey] == 0){ - console.log('PLAYER BOARD'); - } // Get the player the item belongs to let itemPlayer = player[itemKey]; //console.log('Element: '+element+', Player: '+itemPlayer); - calculateItemSizePosition(itemKey); this.printCardToCanvas(itemKey); @@ -149,8 +132,8 @@ class Board{ // Check status, and change border colour for display (for tapped atm) let border = null; - if(cardStatus[itemKey] == 'tapped'){border = '#E0BC00';} - if(cardStatus[itemKey] == 'attacking'){border = '#C92D22';} + if(this.isTapped(itemKey)){border = '#E0BC00';} + if(this.isAttacking(itemKey)){border = '#C92D22';} // Set the card 'cardboard' colour based on the card colour type let fill = null; @@ -287,268 +270,162 @@ class Board{ ctx.font = "10pt Arial"; } - - // Draw Invidual Cards, called by other deck stuff - // Might be put into a card class, makes sense, eh. - drawCard(array, arrayKey, name, positionX, positionY, width, height, fill, border){ - // Card Colour - //console.log('drawCard card: '+JSON.stringify(array[arrayKey])); - let colourId = array[arrayKey].colour; - if(colourId == 0){ fill = '#EEE' } - else if(colourId == 1){ fill = '#0033EE' } - - if(array[arrayKey].tapped){ - border = '#E0BC00'; - console.log('drawCard tapped'); - } - - var cardClickable = new Shape({ - name: name, - x: positionX, - y: positionY, - width: width, - height: height, - fillStyle: fill, - strokeStyle: border - }); - - array[arrayKey]['clickable'] = cardClickable; - array[arrayKey]['clickable'].draw(); - - // Add image - // TODO:half circle for unit Set start angle to 0 and end angle to Math.PI. - // TODO:Ellipse for token (near full size) - // TODO:Octagon for spell - let cardImageContainer = new Shape({ - shape: 'semi', - name: 'cardImageContainer_'+name, - x: positionX+height/3, - y: positionY+width/2, - width: width*.9, - height: height*.9, - fillStyle: "#BBB" - }); - cardImageContainer.draw(); - - // Add card name - let fontSize = width/cardWidth*10; // 10 = baseFontSize of 10pt - ctx.font = "bold "+fontSize+"pt Arial"; - ctx.fillStyle = '#000'; - ctx.fillText( - array[arrayKey]['name'] - , positionX + (ctx.measureText(array[arrayKey]['name']/2).width) - width/4 - , positionY+height*.25 - ); - - // Add card type - ctx.fillText( - array[arrayKey]['type'] - , positionX + (ctx.measureText(array[arrayKey]['type']/2).width) - width/4 - , positionY+height*.7 - ); - // Add text/effect area - if(array[arrayKey]['effect'] !== null){ - ctx.fillText( - array[arrayKey]['effect'] - , positionX + (ctx.measureText(array[arrayKey]['effect']/2).width) - width/4 - , positionY+height*.8 - ); - } - // Attack - ctx.fillText( - array[arrayKey]['atk'] - , positionX + (ctx.measureText(array[arrayKey]['atk']).width) - , positionY+height*.95 - ); - // Add cost - ctx.fillText( - array[arrayKey]['cost'] - , positionX + (ctx.measureText(array[arrayKey]['cost']).width) - , positionY+height*.1 - ); - - // Unbold font for other draws - ctx.font = "10pt Arial"; - } - // boardElement, cardData?, position?, size?, cardStatus, player, listPosition getItems(boardElementId = null, playerId = null, cardStatusId = null, listPositionId = null){ - // So, the intent here is to normalise my nested loop I keep duping (parts of) - // This will recieve each piece of content that can be stored in each ECS element - // Then will loop each individually, setting a new array to be returned - // This new array will then be used for tapping, untapping, moving positions, etc. - - // This is the 'core' of the loop, as it'll keep changing what's in it, removing - // elements at each step. I.e. Will check boardElement for 'mana', removing all other boardElements - // Then with just the 'mana' elements will check the player. OR can return all mana, OR all player items + // Loop each item, building a new (smaller) loop each time an ECSey element + // matches what was passed. This is the core loop for practically every function. let newItems = []; let tempArray = []; // Set to all items in itemArray to start newItems = item; - //let elements = ['deck','board','hand','mana','shield', 'grave']; - // Stuff to be looped, and compared - //let boardElement = {}; - //let cardData = {}; - //let position = {}; - //let size = {}; - //let cardStatus = {}; // tapped, attacking, inspected, untargettable (TODO:maybe used this instead of inEvent later) - //let player = {}; - //let listPosition = {}; - - // These have been re-ordered to try to minise looping - // Example, player in theory halfs the cards instantly, whereas boardElement deck, may do little - // boardElement often will be better though, but??? - - // PLAYER + // Check if each item shares the PLAYERID passed if(playerId !== null){ for(let newItem = 0; newItem < newItems.length; newItem++){ + // newItems[newItem] gets the original itemKey (needed), newItem would be + // the the array index, which would be wrong in most cases in this function. let itemKey = newItems[newItem]; - // If the playerId of item shares the passed playerId + // If the item shares the playerId, add it to the tempArray if(playerId == player[itemKey]){ tempArray.push(newItems[newItem]); } } - // Set newItems to what remains in tempArray + // Set newItems to tempArray so it can be looped again with only what matched newItems = tempArray; } // Reset tempArray so it can be reused tempArray = []; - // CARD STATUS + // Next check if each remaining item shares the CARDSTATUS passed if(cardStatusId !== null){ for(let newItem = 0; newItem < newItems.length; newItem++){ let itemKey = newItems[newItem]; - // If the playerId of item shares the passed playerId + // If the item shares the cardStatusId, add it to the tempArray if(cardStatusId == cardStatus[itemKey]){ tempArray.push(newItems[newItem]); } } - // Set newItems to what remains in tempArray + // Set newItems to tempArray so it can be looped again with only what matched newItems = tempArray; } // Reset tempArray so it can be reused tempArray = []; - // LIST POSITION + // Next check if each remaining item shares the LISTPOSITION passed if(listPositionId !== null){ for(let newItem = 0; newItem < newItems.length; newItem++){ let itemKey = newItems[newItem]; - // If the playerId of item shares the passed playerId + // If the item shares the cardStatusId, add it to the tempArray if(listPositionId == listPosition[itemKey]){ tempArray.push(newItems[newItem]); } } - // Set newItems to what remains in tempArray + // Set newItems to tempArray so it can be looped again with only what matched newItems = tempArray; } // Reset tempArray so it can be reused tempArray = []; - // BOARD ELEMENT - // Loop items for boardElement of elementType passed - // Only do the loop if the element type was passed too, no reason to waste resources + // Next check if each remaining item shares the BOARDELEMENT passed if(boardElementId !== null){ for(let newItem = 0; newItem < newItems.length; newItem++){ - // Add the itemKey to tempArray - // itemKey can be different to the array's elementId, and we want the original itemKey, - // not the new elementId, as that would then add the wrong item - - // Set the itemKey, so things make sense - let itemKey = newItems[newItem]; //newItems[0] could be itemKey 12, so want the content - - // If the boardElement of item shares the passed boardElement add it to current return + let itemKey = newItems[newItem]; + // If the item shares the boardElement, add it to the tempArray if(boardElementId == boardElement[itemKey]){ tempArray.push(newItems[newItem]); } } - // Set newItems to what remains in tempArray + // Set newItems to tempArray so it can be looped again with only what matched newItems = tempArray; } // Reset tempArray so it can be reused tempArray = []; + // Return the new specified itemList return newItems; - - // TODO: May look at restructuring this again. Maybe one loop with each check against - // the element data passed. Depends on which seems fastest, may do a compare on a large - // dataset to see - // TODO: ALSO in different func, Something like x.element.player.status to return the itemKey? } + //TODO: Change vars to newPosition, newElement, newPlayer, oldPosition, oldElement, oldPlayer addFromBoardElement(playerFrom, fromPosition, elementFrom, elementTo, toPosition=null, playerTo=null){ - // Move itemKey fromPosition in elementFrom to toPosition in elementTo - // can also switch item between players (of from and to supplied) + // Move itemKey fromPosition in elementFrom from playerFrom + // to toPosition in elementTo for playerTo + + // If no playerTo provided (typical behavior), pass between elements for same player if(playerTo == null){ playerTo = playerFrom; } - // Check if there's more than 1 thing add that position (something's gone wrong somewhere) + // Check there is only 1 item that exists with the from info let items = this.getItems(elementFrom, playerFrom, null, fromPosition); - if(board.getItems(elementFrom, playerFrom, null, fromPosition).length > 1){ - alert('ERROR: There are more than 1 card being added'); + if(items.length > 1){ + alert('ERROR: There is more than 1 card being added'); } - // First (and only) item returned is the key thins should be done with + // The first (and only) item returned let itemKey = items[0]; - if(listPosition[itemKey] == fromPosition){ - // Check if a toPostion supplied - if(toPosition == null){ - // Get the new position of item based on new boardElement - toPosition = getCurrentPositionAndLength(elementTo, playerTo)[0]+1 - } - //console.log('itemKey: '+itemKey+' fromPosition: '+fromPosition+' elementFrom: '+elementFrom+' elementTo: '+elementTo+' toPosition: '+toPosition+' playerFrom: '+playerFrom+' playerTo: '+playerTo); - - // Move item to it's new position - listPosition[itemKey] = toPosition; - // Move item to it's new element - boardElement[itemKey] = elementTo; - - // Move down(0) the positions of elementFrom, from fromPosition for player - this.moveElementPositions(0, elementFrom, fromPosition, playerFrom); - - this.removeItemStatus(itemKey); - this.drawBoard(); - return 1; // Got a loop that calls a loop, and checks the new values atm, so this keeps counting down + // Check if there is a specific position the item needs to go to + if(toPosition == null){ + // If not get the next available position of the elementTo + toPosition = getCurrentPositionAndLength(elementTo, playerTo)[0]+1 } + //console.log('itemKey: '+itemKey+' fromPosition: '+fromPosition+' elementFrom: '+elementFrom+' elementTo: '+elementTo+' toPosition: '+toPosition+' playerFrom: '+playerFrom+' playerTo: '+playerTo); + // TODO: rename function this lives in to vars accepted by setCardPosition function, more sense + this.setCardPosition(itemKey, toPosition, elementTo, playerTo, fromPosition, elementFrom, playerFrom); + + this.removeItemStatus(itemKey); + this.drawBoard(); + return 1; // Got a loop that calls a loop, and checks the new values atm, so this keeps counting down + } + // This took me a while to think through. It makes sense, don't change. + // Get a pen and paper and just work through an array of 0..5 moving some number about + setCardPosition(card, newPosition, newElement, newPlayer, oldPosition, oldElement, oldPlayer){ + // Move anything in the old boardElement after the old listPosition down by one + // Coming from position 3, moves existing 4..10 down one to 3..9 + // Moving from pos 5 = 6,7,8 go down to 5,6,7 + this.moveElementPositions(0, oldElement, oldPosition, oldPlayer); + + // Move anything in the new boardElement after (including) the new listPosition up by one + // Going to position 3, moves existing 3..10 up one to 4..11 to make space + // Moving back to pos 5 = current 5,6,7 go up to 6,7,8 + this.moveElementPositions(1, newElement, newPosition, newPlayer); + + // Then fit the card into the new gap that's opened up + listPosition[card] = newPosition; + boardElement[card] = newElement; } moveElementPositions(direction, elementFrom, fromPosition, playerFrom){ - - // Move the positions directionally 1 for elementFrom from fromPosition - //console.log(listPosition); - //console.log('Direction: '+direction+' elementFrom: '+elementFrom+' fromPosition: '+fromPosition+' player: '+playerId); - - // Loop the elementFrom, and move positions for anything after - // item taken from position 34, 35..60 need to be moved down to 34..59 + // Loop the elementFrom, and move positions up/down by one let items = this.getItems(elementFrom, playerFrom, null, null); for(let item = 0; item < items.length; item++){ let itemKey = items[item]; - if(listPosition[itemKey] > fromPosition){ - // Move items up, i.e. added to top of deck - if(direction){ - listPosition[itemKey]++; - } - // Move items down, i.e. taken from top of deck + // Move everything after the old position down + // Moving from pos 5 = 6,7,8 go down to 5,6,7 + if(direction == 0 && listPosition[itemKey] > fromPosition){ listPosition[itemKey]--; } + // Move everything from the new position up + // Moving back to pos 5 = current 5,6,7 go up to 6,7,8 + if(direction == 1 && listPosition[itemKey] >= fromPosition){ + listPosition[itemKey]++; + } } } // Draw a card, traditional TCG drawACard(playerId, cardsToDraw = 1){ for(let draw = 0; draw < cardsToDraw; draw++){ - // Move from player1, position 0 (top) of deck, to hand // Check there's space in hand let elementLength = getCurrentPositionAndLength('hand', playerId)[1]; if(elementLength >= maxHandSize){ alert('Hand full '+elementLength+'/'+maxHandSize); - return 0; + return false; } + // Move from players deck to hand, from position 1 (bottom deck) this.addFromBoardElement(playerId, 1, 'deck', 'hand', null, null); } } @@ -622,6 +499,7 @@ class Board{ return itemKey[0]; } + // TODO: Make this work for each element hasSpaceInBoardElement(toElement, toPlayer){ let elementLength = getCurrentPositionAndLength(toElement, toPlayer)[1]; @@ -662,30 +540,48 @@ class Board{ inEvent = ['inspect', cardToInspect]; this.drawBoard(); } + isInEvent(eventToCheck = null){ + if(eventToCheck == null && inEvent){ + // If in any event + return true; + } + if(inEvent && inEvent[0] == eventToCheck){ + // If in specified event + return true; + } + return false; + } cancelInspect(){ - if(inEvent && inEvent[0] == 'inspect'){ - inEvent = null; + if(this.isInEvent('inspect')){ + this.clearEvent(); this.drawBoard(); } } startAttack(itemAttacking){ - // Selects the card that will be attacking - // Rename to attack intent? + // Selects the card that will be attacking - // Do error/legal checks here - if(cardStatus[itemAttacking] == 'tapped'){ + if(this.isTapped(itemAttacking)){ alert('Cannot attack, as tapped'); return false; } - // Set event - inEvent = ['attack', itemAttacking]; - // Set the status of card to attacking for drawing. - // TODO:In future this may be what's used for check (or other in case you can attack with multiple units at once) - cardStatus[itemAttacking] = 'attacking'; + this.setEvent('attack', itemAttacking); + // TODO:In future this MAY be what's used for check + this.setCardStatus(itemAttacking, 'attacking'); this.drawBoard(); } + setEvent(eventName, itemInEvent){ + // TODO: Think this may need a better name + inEvent = [eventName, itemInEvent]; + } + clearEvent(){ + inEvent = null; + } + setCardStatus(itemToUpdate, newStatus = null){ + // TODO: Check if valid status change, if not ignore + cardStatus[itemToUpdate] = newStatus; + } // Do the attack makeAttack(itemDefending, itemAttacking = null){ // TODO: Check if mana owner has any 'block', etc. first, then prevent if so @@ -695,7 +591,7 @@ class Board{ itemAttacking = inEvent[1]; } - if(cardStatus[itemAttacking] == 'tapped'){ + if(this.isTapped(itemAttacking)){ alert('Cannot attack, as tapped'); return false; } @@ -704,8 +600,8 @@ class Board{ // If card on 'board' attacked // Compare attackingCard and defendingCard case 'board': - let atkAttacker = cardData[itemAttacking]; - let atkDefender = cardData[itemDefending]; + let atkAttacker = this.attackOf(itemAttacking); + let atkDefender = this.attackOf(itemDefending); // Does Attacker kill Defender if(atkDefender <= atkAttacker){ @@ -725,11 +621,10 @@ class Board{ case 'shield': // If the shield is tapped 'destroy' it - if(cardStatus[itemDefending] == 'tapped'){ - // Remove from shield, add to hand - // Untap, add to hand (when moving item between status, ANY ITEM. remove status) + if(this.isTapped(itemDefending)){ this.destroyShield(itemDefending); } + // Otherwise tap the shield, so it can be destroyed in future else{ this.tapCard(itemDefending); } @@ -742,6 +637,10 @@ class Board{ this.drawBoard(); } + attackOf(itemKey){ + // TODO: Change this to ECSey element when added + return cardData[itemKey]; + } endAttackFor(itemAttacking){ // Tap the card (this would check if after attack cards taps or not. this.tapCard(itemAttacking); @@ -762,38 +661,30 @@ class Board{ this.drawBoard(); } - // Like everything else, need to consolidate into one function that - // can work for both players, and even more for 2v2 3v1 combats, etc. playShield(fromPosition, fromElement, playerId, cardsToPlay = 1){ for(let shieldNo = 0; shieldNo < cardsToPlay; shieldNo++){ - // Check there's space for shield TODO: change to locationTo - // TODO: Normalise this for all element/player combos - let elementLength = getCurrentPositionAndLength('shield', playerId)[1]; - if(elementLength >= maxShield){ - alert('Shield full '+elementLength+'/'+maxShield); - // Kill loop if there's too many shiled already, no need re-notifying - return 0; + let shieldLength = this.shieldCount(playerId); + // Check shield zone isn't already full + if(shieldLength >= maxShield){ + alert('Shield full '+shieldLength+'/'+maxShield); + return false; } // Move from player, position 0 (top) of deck, to hand (next available position) this.addFromBoardElement(playerId, fromPosition, fromElement, 'shield', null, null); } } + shieldCount(playerId){ + return getCurrentPositionAndLength('shield', playerId)[1]; + } - playMana(fromPosition, fromElement, fromPlayer, cardsToPlay = 1){ - // Move from player0, fromPosition of hand (for now), to mana - // TODO: FOR ALL addFromBoardElements, if 'fromPosition' not passed get the - // fromPosition and boardElementFrom from the itemId (will need to change to pass this) - console.log('playMana('+fromPosition+','+fromElement+','+cardsToPlay+')'); + playMana(fromPosition, fromElement, fromPlayer){ this.addFromBoardElement(fromPlayer, fromPosition, fromElement, 'mana', null, null); } // HELPER METHODS, to simplify code-base for me in the future destroyShield(itemKey){ - // Adds from 'shield' to 'hand' boardElement - // Sets the listPosition to the next in line for new boardElement - // Changes the listPosition of each item in previous boardElement - // All for same player, although below playerFrom/playerTo can be set to switch between players + // Adds from 'shield' to 'hand' boardElement for player shield belongs to // TODO:Check if shield can be destroyed (instantly, i.e. poisontouch, or some mechanic/spell akin) @@ -808,16 +699,19 @@ class Board{ for(let item = 0; item < items.length; item++){ let itemKey = items[item]; // If ANY of their shields are untapped, you can't destroy target - if(cardStatus[itemKey] != 'tapped'){ + if(!board.isTapped(itemKey)){ alert('There is an untapped shield, cannot destroy target'); return false; } } // Shield is now destroyed, move it from shield to owners hand (for the catchup mechanic) - this.addFromBoardElement(player[itemKey], listPosition[itemKey], boardElement[itemKey], 'hand', null, null); + this.addShieldToHand(player[itemKey], listPosition[itemKey]); return true; } + addShieldToHand(playerFrom = null, listPositionFrom = null){ + this.addFromBoardElement(playerFrom, listPositionFrom, 'shield', 'hand', null, null); + } sendToGrave(itemKey){ console.log('SendToGrave: '+itemKey); @@ -830,10 +724,12 @@ class Board{ cardStatus[itemKey] = 'tapped'; // Do any other 'on tap' effects, etc. in the future } + tap(itemKey){ tapCard(itemKey); } untapCard(itemKey){ cardStatus[itemKey] = null; // Do any other 'on tap' effects, etc. in the future } + untap(itemKey){ untapCard(itemKey); } remainingShieldCount(playerId){ return getCurrentPositionAndLength('shield', playerId)[1]; } @@ -845,21 +741,24 @@ class Board{ if(cardStatus[itemKey] == 'tapped'){ return true; } return false; } + isAttacking(itemKey){ + if(cardStatus[itemKey] == 'attacking'){ return true; } + return false; + } } // Run board commands here for testing let board = new Board; -// TODO: TEMP!! Replace soon -createDeck(); -//createDeckList(playerDeck, deckCount, 0); -//createDeckList(opponentDeck, deckCountOpponent, 1); +// Fill each players deck with their cards +createDecks(); -// Play 4 shield from top (0) of each players deck +// Play shield from top of each players deck to the maximum allowed (4 typically) for(let currentPlayer = 0; currentPlayer <= players-1; currentPlayer++){ - board.playShield(1, 'deck', currentPlayer, 4); + board.playShield(1, 'deck', currentPlayer, maxShield); } +// Draw the graphics of the board/game board.drawBoard(true); @@ -882,7 +781,7 @@ canvas.addEventListener('contextmenu', function(event) { // Check the item has a size and position if(itemKey in size && itemKey in position){ // Compare the event XY position to the item - if(clickableCheck(x,y,false,itemKey)){ + if(clickableCheck(x,y,itemKey)){ // Only want to happen once (for now) // Maybe in future add to hand would trigger another event if there's an effect? @@ -898,7 +797,7 @@ canvas.addEventListener('contextmenu', function(event) { // If there's an attack event, target other cards // If there is an event, the event is attack event, and the item currently loop // is the same one as currently in the event - if(inEvent && inEvent[0] == 'attack' && itemKey == inEvent[1]){ + if(board.isInEvent('attack') && itemKey == inEvent[1]){ board.cancelAttackFor(itemKey); } break; @@ -948,7 +847,7 @@ canvas.addEventListener('click', function(event) { // Check the item has a size and position if(itemKey in size && itemKey in position){ // Compare the event XY position to the item - if(clickableCheck(x,y,false,itemKey)){ + if(clickableCheck(x,y,itemKey)){ // Only want to happen once (for now) // Maybe in future add to hand would trigger another event if there's an effect? @@ -974,7 +873,7 @@ canvas.addEventListener('click', function(event) { // yourPlayerId in for now to prevent using opponents card // TODO:the cards may be used to attack, there will be another // check like 'canUseOpponentsBoard' or something - if(!inEvent && cardStatus[itemKey] != 'tapped' && playerId == yourPlayerId){ + if(!inEvent && !board.isTapped(itemKey) && playerId == yourPlayerId){ board.startAttack(itemKey); break; } @@ -1025,34 +924,25 @@ canvas.addEventListener('click', function(event) { }, false); -function clickableCheck(x,y,clickable=false,itemKey=false){ +function clickableCheck(cursorX,cursorY,itemKey){ // Collision detection between clicked offset and clickableItems // https://stackoverflow.com/a/9880302 - - // Temp solution to add the check while the old way also exists - // simultaneously. It works, so that's nice - if(clickable === false && itemKey !== false){ - clickable = {}; - //console.log(clickable); - //console.log(itemKey); - clickable.x = position[itemKey][0]; - clickable.y = position[itemKey][1]; - clickable.width = size[itemKey][0]; - clickable.height = size[itemKey][1]; - //console.log(clickable); - } + let itemX = position[itemKey][0]; + let itemY = position[itemKey][1]; + let itemWidth = size[itemKey][0]; + let itemHeight = size[itemKey][1]; // Debug Stuff let debug = false if(debug){ - console.log(clickable.y+' <'); - console.log(y+ '<') - console.log(clickable.y+clickable.height); + console.log(itemY+' <'); + console.log(cursorY+ '<') + console.log(itemY+itemHeight); } if( - y > clickable.y && y < clickable.y + clickable.height - && x > clickable.x && x < clickable.x + clickable.width) + cursorY > itemY && cursorY < itemY + itemHeight + && cursorX > itemX && cursorX < itemX + itemWidth) { return true; } @@ -1061,7 +951,7 @@ function clickableCheck(x,y,clickable=false,itemKey=false){ } -function createDeck(){ +function createDecks(){ // Create a 'realDeck' element for each player for(let i = 0; i < players; i++){ item.push(itemCount); @@ -1132,15 +1022,9 @@ function shuffleDeck(playerId){ let items = board.getItems('deck', playerId, null, null); for(let item = 0; item < items.length; item++){ let itemKey = items[item]; - //console.log('ITEM KEY: '+itemKey); - //console.log('OLD LIST POSITION: '+listPosition[itemKey]); - listPosition[itemKey] = tempDeck[item]; - - //console.log('NEW LIST POSITION: '+listPosition[itemKey]); } - } function untapZone(elementFrom, playerFrom){ @@ -1156,7 +1040,6 @@ function untapAllZones(currentPlayer = null){ currentPlayer = 0; } for(let currentPlayer = 0; currentPlayer <= players-1; currentPlayer++){ - let elements = ['deck','board','hand','mana','shield', 'grave']; // Loop all the elements, and utap each card in the zone for(let element = 0; element < elements.length; element++){ untapZone(elements[element], currentPlayer); @@ -1177,11 +1060,9 @@ function getCurrentPositionAndLength(elementName, playerId){ highestListPosition = listPosition[itemKey]; } length++; - } return [highestListPosition, length]; - } function calculateItemSizePosition(itemKey){