diff --git a/public/board.js b/public/board.js index dc20c75..8a237f9 100644 --- a/public/board.js +++ b/public/board.js @@ -8,36 +8,34 @@ const cardHeight = 120; const cards = new Image(); const back = new Image(); -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'] = []; - -// TODO: Uniform the arrays to player and opponent/different playesr -let playerHand = []; -let opponentHand = []; -let playerBoard = []; -let opponentBoard = []; -let playerDeck = []; -let opponentDeck = []; -let playerShield = []; -let opponentShield = []; -let playerMana = []; -let opponentManaZone = []; - -let deckCount = 60; -let deckCountOpponent = 60; - -let cardsInOpponentsHand = 0; +// 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 = ['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 = []; +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 (TODO:maybe used this instead of inEvent later) +let player = {}; +let listPosition = {}; +let inEvent = null; + +// 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 + const maxHandSize = 4; const maxBoardSize = 3; -const maxShield = 4; - -let inspectCard = null; -let attackingCard = null; -let gameWin = 0; +const maxShield = 2; // Gonna need lots of refactoring, and sorting class Board{ @@ -50,33 +48,28 @@ 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 ctx.fillText(name, 0, 10); - this.drawCardsOnBoard(); - this.drawCardsOnBoardOpponent(); - - this.drawDeck(); - this.drawDeckOpponent(); - - this.drawShield(); - this.drawShieldOpponent(); - - this.drawHand(); - this.drawOpponentHand(); - - this.drawMana(); - this.drawPlayerNames('Nathan', 'Evil Nathan'); - if(gameWin){ + this.drawItems(); // Atop most everything atm for testing + + if(this.checkGameWin() == true){ this.drawWin(); } + } - this.drawInspectedCard(); + checkGameWin(){ + // 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; } drawWin(){ @@ -102,28 +95,65 @@ 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); } } - // 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' } + drawItems(){ + // Loop all items + for(let itemKey = 0; itemKey < item.length; itemKey++){ + // 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' || element == 'grave'){ + continue; + } + + // Draw Elements + // Loop each item remaining, draw them + if(itemKey in boardElement && boardElement[itemKey] == element){ + // Get the player the item belongs to + let itemPlayer = player[itemKey]; + //console.log('Element: '+element+', Player: '+itemPlayer); + calculateItemSizePosition(itemKey); - if(array[arrayKey].tapped){ - border = '#E0BC00'; - console.log('drawCard tapped'); + this.printCardToCanvas(itemKey); + } + } } + } - var cardClickable = new Shape({ + 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(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; + 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 if(colourId == 2){ fill = '#ED344A'; } + }else{ + fill = '#B0B0B0'; + } + + 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, @@ -132,14 +162,52 @@ class Board{ fillStyle: fill, strokeStyle: border }); + shape.draw(); + + 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(); + + // Draw deck count text + ctx.fillStyle = '#000'; + ctx.fillText(deckLength, textx, texty); + } + + + } - array[arrayKey]['clickable'] = cardClickable; - array[arrayKey]['clickable'].draw(); + 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 - // half circle for unit Set start angle to 0 and end angle to Math.PI. - // Ellipse for token (near full size) - // Octagon for spell + // 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, @@ -147,44 +215,54 @@ class Board{ y: positionY+width/2, width: width*.9, height: height*.9, - fillStyle: "#BBB" + 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( - array[arrayKey]['name'] - , positionX + (ctx.measureText(array[arrayKey]['name']/2).width) - width/4 + cardData[itemKey]['name'] + , positionX + (ctx.measureText(cardData[itemKey]['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 + cardData[itemKey]['type'] + , positionX + (ctx.measureText(cardData[itemKey]['type']/2).width) - width/4 , positionY+height*.7 ); // Add text/effect area - if(array[arrayKey]['effect'] !== null){ + if(cardData[itemKey]['effect'] !== null){ ctx.fillText( - array[arrayKey]['effect'] - , positionX + (ctx.measureText(array[arrayKey]['effect']/2).width) - width/4 + cardData[itemKey]['effect'] + , positionX + (ctx.measureText(cardData[itemKey]['effect']/2).width) - width/4 , positionY+height*.8 ); } // Attack ctx.fillText( - array[arrayKey]['atk'] - , positionX + (ctx.measureText(array[arrayKey]['atk']).width) + cardData[itemKey]['atk'] + , positionX + (ctx.measureText(cardData[itemKey]['atk']).width) , positionY+height*.95 ); // Add cost ctx.fillText( - array[arrayKey]['cost'] - , positionX + (ctx.measureText(array[arrayKey]['cost']).width) + cardData[itemKey]['cost'] + , positionX + (ctx.measureText(cardData[itemKey]['cost']).width) , positionY+height*.1 ); @@ -192,666 +270,988 @@ 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(); - - // 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(); - - ctx.fillStyle = '#000'; - // TODO: Center in the circle - 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); + // boardElement, cardData?, position?, size?, cardStatus, player, listPosition + getItems(boardElementId = null, playerId = null, cardStatusId = null, listPositionId = null){ + // 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; + + // 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 item shares the playerId, add it to the tempArray + if(playerId == player[itemKey]){ + tempArray.push(newItems[newItem]); + } + } + // Set newItems to tempArray so it can be looped again with only what matched + newItems = tempArray; + } + // Reset tempArray so it can be reused + tempArray = []; + + // 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 item shares the cardStatusId, add it to the tempArray + if(cardStatusId == cardStatus[itemKey]){ + tempArray.push(newItems[newItem]); + } + } + // Set newItems to tempArray so it can be looped again with only what matched + newItems = tempArray; + } + // Reset tempArray so it can be reused + tempArray = []; + + // 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 item shares the cardStatusId, add it to the tempArray + if(listPositionId == listPosition[itemKey]){ + tempArray.push(newItems[newItem]); + } + } + // Set newItems to tempArray so it can be looped again with only what matched + newItems = tempArray; + } + // Reset tempArray so it can be reused + tempArray = []; - 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; + // Next check if each remaining item shares the BOARDELEMENT passed + if(boardElementId !== null){ + for(let newItem = 0; newItem < newItems.length; newItem++){ + let itemKey = newItems[newItem]; + // If the item shares the boardElement, add it to the tempArray + if(boardElementId == boardElement[itemKey]){ + tempArray.push(newItems[newItem]); + } + } - this.drawCard(playerHand, i, name, positionX, positionY, width, height, fill); + // 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; } - drawOpponentHand(){ - // Opponents Hand/Cards in Hand - for (let i = 0; i < opponentHand.length; i++) { + //TODO: Change vars to newPosition, newElement, newPlayer, oldPosition, oldElement, oldPlayer + addFromBoardElement(playerFrom, fromPosition, elementFrom, elementTo, toPosition=null, playerTo=null){ + // Move itemKey fromPosition in elementFrom from playerFrom + // to toPosition in elementTo for playerTo - let name = 'cardInOpponentsHand_'+(i+1); + // If no playerTo provided (typical behavior), pass between elements for same player + if(playerTo == null){ + playerTo = playerFrom; + } - let cardPadding = 10; - let fill = '#'+i+i+'DD00'; + // Check there is only 1 item that exists with the from info + let items = this.getItems(elementFrom, playerFrom, null, fromPosition); + if(items.length > 1){ + alert('ERROR: There is more than 1 card being added'); + } - // 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; + // The first (and only) item returned + let itemKey = items[0]; - this.drawCard(opponentHand, i, name, positionX, positionY, width, height, fill); + // 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); - } - - drawCards(){} + // TODO: rename function this lives in to vars accepted by setCardPosition function, more sense + this.setCardPosition(itemKey, toPosition, elementTo, playerTo, fromPosition, elementFrom, playerFrom); - // Draw a card, traditional TCG - drawACard(cardsToDraw = 1){ - // 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); - return 0; + 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){ + // 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]; + // 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]++; } - - // 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(); } } - drawACardOpponent(cardsToDraw = 1){ + // Draw a card, traditional TCG + drawACard(playerId, cardsToDraw = 1){ for(let draw = 0; draw < cardsToDraw; draw++){ - if(opponentHand.length >= maxHandSize){ - alert('Hand full '+opponentHand.length+'/'+maxHandSize); - return 0; + + // Check there's space in hand + let elementLength = getCurrentPositionAndLength('hand', playerId)[1]; + if(elementLength >= maxHandSize){ + alert('Hand full '+elementLength+'/'+maxHandSize); + return false; } - // 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(); + // Move from players deck to hand, from position 1 (bottom deck) + this.addFromBoardElement(playerId, 1, 'deck', 'hand', null, null); } } + // Currently only functionality in hand + playCardToBoard(positionFrom, fromElement, toElement, fromPlayer, toPlayer = null, cardsToPlay = 1){ - drawCardsOnBoard(){ - // DUPE OF DRAW PLAYER HAND FOR NOW!!! - for (let i = 0; i < playerBoard.length; i++) { - - let name = 'cardOnBoard_'+(i+1); + // TODO: if from hand, use mana according to the card cost + mana types + if(toPlayer === null){ + toPlayer = fromPlayer; + } - let cardPadding = 10; - let fill = '#'+i+i+'CC00'; + // Loop probably not needed, but may be for eg. 'play X cards from top of deck' + for(let play = 0; play < cardsToPlay; play++){ - // 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; + // Check there's space on the board/mana zone/shield/etc + if(!this.hasSpaceInBoardElement(toElement, toPlayer)){ + alert('No space in element'); + return false; + } - if(attackingCard !== null && playerBoard[i].name == attackingCard[0].name){ - border = '#FF0000'; + let itemKey = this.getItemKey(fromElement, positionFrom, fromPlayer); + 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.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 + // 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{ + continue; + } + } + } } - this.drawCard(playerBoard, i, name, positionX, positionY, width, height, fill, border); - } - } - drawCardsOnBoardOpponent(){ - for (let i = 0; i < opponentBoard.length; i++) { + // Move from player0, position 0 (top) of deck, to hand, to pos(null/auto) for toPlayer + this.addFromBoardElement(fromPlayer, positionFrom, fromElement, toElement, null, toPlayer); + } - let name = 'cardOnBoardOpponent_'+(i+1); + this.drawBoard(); + } - let cardPadding = 10; - let fill = '#'+i+i+'AA00'; + getItemKey(boardElementId, listPositionId, playerFrom){ + let itemKey = this.getItems(boardElementId, playerFrom, 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]; + } + + // TODO: Make this work for each element + hasSpaceInBoardElement(toElement, toPlayer){ - // 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; + let elementLength = getCurrentPositionAndLength(toElement, toPlayer)[1]; - this.drawCard(opponentBoard, i, name, positionX, positionY, width, height, fill); + if(elementLength >= maxHandSize){ + alert('Board full '+elementLength+'/'+maxHandSize); + return false; } + return true; } + canPayMana(itemToPlay, playerId){ + // Check player has enough mana + if(this.getItems('mana', playerId, null, null).length < cardData[itemToPlay].cost){ + return 'Not enough mana'; + } - // Currently only functionality in hand - playCardToBoard(index){ - // Get the card data - let cardPlayed = playerHand[index]; + // TODO: Check mana colours are available to play, then tap them + // TODO: Multicolours, and X of same colour checks 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; + // For now, until adding colour, and other attributes to ECS modal + let manaColourRequired = cardData[itemToPlay].colour; + console.log(manaColourRequired); + 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)){ + manaUsed.push(itemKey); // This would be how I'd loop for X colour, or multi + console.log(manaUsed); + return true; + } } - 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; - } - }); + return 'Do not have correct mana requirements'; + } - if(!canPlay){ - alert('Mana conditions not met, right click hand unit to play as mana'); - return 0; - } + inspectCard(cardToInspect){ + // Set inspectedCard (for now) to the card itemKey + 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(this.isInEvent('inspect')){ + this.clearEvent(); + this.drawBoard(); + } + } - // Tap mana to be used - manaUsed.forEach(function(cardKey, key){ - playerMana[cardKey].tapped = true; - }); - - console.log(playerMana); + startAttack(itemAttacking){ + // Selects the card that will be attacking - // Remove from hand - playerHand.splice(index, 1); - // Add to board - playerBoard.push(cardPlayed); + if(this.isTapped(itemAttacking)){ + alert('Cannot attack, as tapped'); + return false; + } + this.setEvent('attack', itemAttacking); + // TODO:In future this MAY be what's used for check + this.setCardStatus(itemAttacking, 'attacking'); this.drawBoard(); } - playCardToBoardFromDeckOpponent(){ + 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 - // Random card from deck - let cardToDraw = Math.floor(Math.random() * deckCount); - let cardPlayed = opponentDeck[cardToDraw]; + // If itemAttacking not defined, use the item from inEvent + if(itemAttacking == null){ + itemAttacking = inEvent[1]; + } - if(opponentBoard.length >= maxBoardSize){ - alert('No space on board to play card. '+opponentBoard.length+'/'+maxBoardSize); - return 0; + if(this.isTapped(itemAttacking)){ + alert('Cannot attack, as tapped'); + return false; } - // Remove from deck - opponentDeck.splice(cardToDraw, 1); - // Add to board - opponentBoard.push(cardPlayed); + switch (boardElement[itemDefending]) { + // If card on 'board' attacked + // Compare attackingCard and defendingCard + case 'board': + let atkAttacker = this.attackOf(itemAttacking); + let atkDefender = this.attackOf(itemDefending); - this.drawBoard(); - } - inspectOpponentBoard(index){ - // Get the card data - inspectCard = [opponentBoard, index]; + // Does Attacker kill Defender + if(atkDefender <= atkAttacker){ + this.sendToGrave(itemDefending); + } - 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; + // Does Defender kill Attacker + if(atkAttacker <= atkDefender){ + this.sendToGrave(itemAttacking); + 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(this.isTapped(itemDefending)){ + this.destroyShield(itemDefending); + } + // Otherwise tap the shield, so it can be destroyed in future + else{ + this.tapCard(itemDefending); + } + // End the attacker card attack 'phase' + this.endAttackFor(itemAttacking); - this.drawCard(inspectCard[0], inspectCard[1], name, positionX, positionY, width, height, '#D1D100'); - console.log('inspect'); + break; } - } - // Selects the card that will be attacking - // Stop other actions besides selecting opponent/opponent unit - // Can cancel, will do later - startAttack(index){ - // Can probably combine attacking/inspect, and set another array element to 'attacking', 'inspecting', etc. - attackingCard = [playerBoard[index], index]; + 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; - } - - playerBoard[attackingCard[1]].tapped = true; - this.endAttack(); - return 1; - } + 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); - if(defendingCard.atk <= attackingCard[0].atk){ - array.splice(index, 1); - // Need to push to grave, etc. here in future too + // If the item attacking was from the 'attack' event, remove the event + if(itemAttacking == inEvent[1]){ + inEvent = null; } - if(attackingCard[0].atk <= defendingCard.atk){ - playerBoard.splice(attackingCard[1], 1); - }else{ - playerBoard[attackingCard[1]].tapped = true; - } - 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(); } - // 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){ - for(let shieldNo = 0; shieldNo < shieldsToPlay; shieldNo++){ - if(playerShield.length >= maxShield){ - alert('Shield zone full '+playerShield.length+'/'+maxShield); - return 0; + playShield(fromPosition, fromElement, playerId, cardsToPlay = 1){ + for(let shieldNo = 0; shieldNo < cardsToPlay; shieldNo++){ + let shieldLength = this.shieldCount(playerId); + // Check shield zone isn't already full + if(shieldLength >= maxShield){ + alert('Shield full '+shieldLength+'/'+maxShield); + return false; } - // 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(); + // Move from player, position 0 (top) of deck, to hand (next available position) + this.addFromBoardElement(playerId, fromPosition, fromElement, 'shield', null, null); } } - 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(); - } + shieldCount(playerId){ + return getCurrentPositionAndLength('shield', playerId)[1]; } - 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); - } + playMana(fromPosition, fromElement, fromPlayer){ + this.addFromBoardElement(fromPlayer, fromPosition, fromElement, 'mana', null, null); } - 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); + // HELPER METHODS, to simplify code-base for me in the future + destroyShield(itemKey){ + // 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) - this.drawCard(opponentShield, i, name, positionX, positionY, width, height, fill); + // 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; } - } - - playMana(index, fromDeck = 0){ - 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); + // 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.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 + if(!board.isTapped(itemKey)){ + alert('There is an untapped shield, cannot destroy target'); + return false; + } } - playerMana.push(manaCard); - - this.drawBoard(); + // Shield is now destroyed, move it from shield to owners hand (for the catchup mechanic) + this.addShieldToHand(player[itemKey], listPosition[itemKey]); + return true; + } + addShieldToHand(playerFrom = null, listPositionFrom = null){ + this.addFromBoardElement(playerFrom, listPositionFrom, 'shield', 'hand', null, null); } - 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; + 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); + } - this.drawCard(playerMana, i, name, positionX, positionY, width, height, fill); - } + tapCard(itemKey){ + // Set the cardStatus to tapped + 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]; + } + removeItemStatus(itemKey){ + // 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; + } + isAttacking(itemKey){ + if(cardStatus[itemKey] == 'attacking'){ return true; } + return false; } } -// TEMP!! -createDeckList(playerDeck, deckCount); -createDeckList(opponentDeck, deckCountOpponent); - // Run board commands here for testing let board = new Board; -//board.initBoard(); -// TEMP: Play a card on opponents board (from their deck) -board.playCardToBoardFromDeckOpponent(); +// Fill each players deck with their cards +createDecks(); -board.drawBoard(); +// 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, maxShield); +} -board.playShield(4); -board.playShieldOpponent(4); +// Draw the graphics of the board/game +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; - // # PLAYER HAND - playerHand.forEach(function(card, index){ + console.log('RIGHT CLICK X: '+x+' Y: '+y); - let clickable = card.clickable; + for(let itemKey = 0; itemKey < item.length; itemKey++){ - if(clickableCheck(x,y,clickable) && !specialEvent){ - board.playMana(index); - board.drawBoard(); + if(elements[itemKey] == 'deck'){ + 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 + 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? + + // 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 + case 'board': + // 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 + if(board.isInEvent('attack') && itemKey == inEvent[1]){ + board.cancelAttackFor(itemKey); + } + break; + case 'hand': + // Can be played as mana (right click for now) + // Play item from boardElement hand. To boardElement mana (explanitory) + if(!inEvent){ + board.playMana(listPosition[itemKey], 'hand', playerId); + } + break; + default: + break; + } + board.drawBoard(); + return true; + } } - }); - // 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(''); - - // 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; - } var x = event.pageX - canvasLeft, y = event.pageY - canvasTop; - // 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'); + // 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('LEFT CLICK X: '+x+' Y: '+y); + // TODO: Normalise this too + for(let itemKey = 0; itemKey < item.length; itemKey++){ + if(boardElement[itemKey] == 'deck'){ + continue; }else{ - console.log('not inspected card'); - // Stop inspecting card if player clicks off it - inspectCard = null; - board.drawBoard(); + //printECSData([itemKey]); + } + + // 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,itemKey)){ + // 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 + // TODO: Change inEvent locations, and checks elsewhere? + // TODO: Make existing mechanics ECSey + case 'realDeck': + if(!inEvent){ + 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 + // etc. + + // 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 && !board.isTapped(itemKey) && playerId == yourPlayerId){ + board.startAttack(itemKey); + break; + } + // opponentBoard + // If there's an attack event, target other cards + // 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); + break; + } + + // 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) + if(!inEvent && playerId != yourPlayerId){ + board.inspectCard(itemKey); + break; + } + else if(inEvent && inEvent[0] == 'inspect' && inEvent[1] == itemKey){ + board.cancelInspect(); + break; + } + + break; + case 'hand': + // TODO: Ensure it can be played + if(!inEvent){ + board.playCardToBoard(listPosition[itemKey], 'hand', 'board', playerId, playerId, 1); + } + break; + case 'shield': + // 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; + default: + break; + } + board.drawBoard(); + return true; + } } } - // # PLAYER DECK - clickable = clickableItems['deckSprite']; +}, false); + +function clickableCheck(cursorX,cursorY,itemKey){ + // Collision detection between clicked offset and clickableItems + // https://stackoverflow.com/a/9880302 + let itemX = position[itemKey][0]; + let itemY = position[itemKey][1]; + let itemWidth = size[itemKey][0]; + let itemHeight = size[itemKey][1]; - // 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 + // Debug Stuff + let debug = false + if(debug){ + console.log(itemY+' <'); + console.log(cursorY+ '<') + console.log(itemY+itemHeight); + } - // For now this will be fine, as it functions - if(clickableCheck(x,y,clickable) && !specialEvent){ - board.drawACard(); + if( + cursorY > itemY && cursorY < itemY + itemHeight + && cursorX > itemX && cursorX < itemX + itemWidth) + { + return true; } - // # OPPONENT DECK - clickable = clickableItems['deckOpponentSprite']; + return false; + +} + +function createDecks(){ + // 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++; + } - if(clickableCheck(x,y,clickable) && !specialEvent){ - board.drawACardOpponent(); + // Loop again and create the deckLists + for(let i = 0; i < players; i++){ + createDeckList(i); + } + +} +// 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 + // 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 + + // Set the player + player[itemCount] = playerId; + // 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.getItems(null, playerId); - // # PLAYER HAND - playerHand.forEach(function(card, index){ + shuffleDeck(playerId); +} - let clickable = card.clickable; +function shuffleDeck(playerId){ - if(clickableCheck(x,y,clickable) && !specialEvent){ + // Create a tempDeck array of same length of the player deck + let deckLength = getCurrentPositionAndLength('deck', playerId)[1]; + let tempDeck = Array.from(Array(deckLength).keys()) - board.playCardToBoard(index); - - // This would actually fire off a socketIO doodad, that would then return - // data, and redraw. But for now (UI test) + // 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] ]; + } - // Add to board - board.drawBoard(); - } - }); + // For each item in the actual deck, set the listPosition to the random number from tempDeck + let items = board.getItems('deck', playerId, null, null); + for(let item = 0; item < items.length; item++){ + let itemKey = items[item]; + listPosition[itemKey] = tempDeck[item]; + } - // # 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(); +function untapZone(elementFrom, playerFrom){ + 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); } + } + board.drawBoard(); +} +function untapAllZones(currentPlayer = null){ + if(currentPlayer === null){ + currentPlayer = 0; + } + for(let currentPlayer = 0; currentPlayer <= players-1; currentPlayer++){ + // Loop all the elements, and utap each card in the zone + for(let element = 0; element < elements.length; element++){ + untapZone(elements[element], currentPlayer); } - }); - // # OPPONENT BOARD - opponentBoard.forEach(function(card, index){ - let clickable = card.clickable; + } +} +function getCurrentPositionAndLength(elementName, playerId){ - if(clickableCheck(x,y,clickable)){ - // Check if card if getting attacked - if(attackingCard !== null){ - board.makeAttack(index); - } + let highestListPosition = 0; + let length = 0; - if(!specialEvent){ - board.inspectOpponentBoard(index); - } - board.drawBoard(); - } - }); - // # OPPONENT SHIELD - opponentShield.forEach(function(card, index){ - let clickable = card.clickable; + let items = board.getItems(elementName, playerId, null, null); + for(let item = 0; item < items.length; item++){ + let itemKey = items[item]; - if(clickableCheck(x,y,clickable)){ - // Check if card if getting attacked - if(attackingCard !== null){ - board.makeAttack(index, opponentShield, 'opponentShield'); - } - board.drawBoard(); + if(listPosition[itemKey] >= highestListPosition){ + highestListPosition = listPosition[itemKey]; } - }); + length++; + } -}, false); + return [highestListPosition, length]; +} -function clickableCheck(x,y,clickable){ +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]; + + let itemListPositionLength = getCurrentPositionAndLength(itemElement, itemPlayer); + let itemListPositionNext = itemListPositionLength[0]; + let itemListLength = itemListPositionLength[1]; + + let cardMargin = 10; + let positionX = 0; + let positionY = 0; + let width = 0; + let height = 0; + + 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; - // Debug Stuff - let debug = false - if(debug){ - console.log(clickable.y+' <'); - console.log(y+ '<') - console.log(clickable.y+clickable.height); + } + 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( - y > clickable.y && y < clickable.y + clickable.height - && x > clickable.x && x < clickable.x + clickable.width) - { - return true; + if(itemPlayer == 1 && itemElement == 'board'){ + 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)) - (cardMargin * (i+1))); + positionY = 20; + width = cardWidth; + height = cardHeight; + } + if(itemPlayer == 1 && itemElement == 'mana'){ + // TODO: Opponent 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)) - (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)) - (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; + } + + // Inspected Card + // 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; + 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 + size[itemKey] = [width, height]; + position[itemKey] = [positionX,positionY]; - return 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 -function createDeckList(deck, deckCount){ - 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({ - 'name':'CardName '+(i+1) - , 'cost':1 - , 'atk':1 - , 'def':1 - , 'rarity': 'common' - , 'effect':effect - , 'type':'human' - , 'colour':colour - , 'tapped':false - }); +// 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; } + let itemOrCard = document.getElementById("itemOrCardData").value; + getItemsAndPrint(boardElementId, playerId, cardStatusId, listPositionId, itemOrCard); +} +function getItemsAndPrint(boardElementId = null, playerId = null, cardStatusId = null, listPositionId = null, itemOrCard = 'item'){ + let items = board.getItems(boardElementId, playerId, cardStatusId, listPositionId); + if(itemOrCard == 'card'){ + console.log('----- CardData -----'); + printCardData(items); + }else{ + console.log('----- ItemData -----'); + printECSData(items); } + console.log('Items array length: '+items.length); } +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] + ); + } +} +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 untap(array){ - console.log(array); - array.forEach(function(card, key){ - array[key].tapped = false; - }); - board.drawBoard(); } -function untapAll(){ - untap(playerMana); - untap(playerBoard); - untap(opponentShield); +function echoCards(){ + console.log(cardArray); +} +function echoCardsInDeck(playerId){ + // Get all the cards that belong to player + 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 + 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 3a95905..8cc583f 100644 --- a/public/index.html +++ b/public/index.html @@ -16,9 +16,48 @@ - + + + + + +