From 2e8670724393f12ecd8edb83ff0bb4b1567f8291 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 20 Oct 2024 12:09:18 +0100 Subject: [PATCH 01/13] Change check for mana available vs card mana cost --- public/board.js | 84 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 11 deletions(-) diff --git a/public/board.js b/public/board.js index 9433fbe..2ccf13c 100644 --- a/public/board.js +++ b/public/board.js @@ -579,23 +579,85 @@ class Board{ return 'Not enough mana'; } - // 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 manaColourRequired = cardData[itemToPlay].colour; - console.log(manaColourRequired); + // Check if the player has X amount of each mana colour required + // may not be needed to tap them all (if cost reduced), but they need + // to have those colours available. + // Setting them to 0 to start so they can be added to. Could be nicer + let manaAvailable = {0:0, 1:0, 2:0, 3:0, 4:0}; + + // TODO: Thought, maybe instead of tapping colour used, it's just if you + // have the colour? May be a silly thought, but + + // Loop the card to be played, and total its mana requirements + let manaRequired = this.getManaTotalOf(itemToPlay); + + + // player check for this may need changing for "play from opp hand" etc? let items = this.getItems('mana', player[itemToPlay], null, null); for(let item = 0; item < items.length; item++){ + // Looping the mana to check player has equal mana/colours to req. 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; + + // Check if the mana is tapped. Ignore if it is (for now) + if(this.isTapped(itemKey)){ + continue; + } + + + // Loop the mana card's colours + // can be multi-coloured, and can be used as diff costs + // TODO: This currently takes a White/Red mana as 2 available manas + // when it should be 1 available of either type... + // TODO: FOR NOW, the colour of the mana is the primary colour + // will set 'manaColour' in DB at some point. So multi-colour + // cards aren't all those when in mana (ie. 6 colour decks can't play + // everything all the time) + let manaType = null; // TODO: Will use the highest mana req as it's colour for now + let manaColours = cardColours[itemKey]; + for(let i = 0; i < manaColours.length; i++){ + // Set mana colour for card if there isn't one + if(manaType == null){ manaType = manaColours[i]; } + // Check each other colour, use the highest cost colour + // as the colour type for this specific mana + // TODO: Do better, and nicer, manaType in DB with the colour? + if(manaColours[i][1] > manaType[1]){ + manaType = manaColours[i]; + } } + let colourId = manaType[0]; + manaAvailable[colourId] += 1; + } + + // If the manaReq is satiated by the manaAvailable then return true + for (const manaColour in manaRequired) { + console.log('req'); + console.log(manaRequired[manaColour]); + console.log('av'); + console.log(manaAvailable[manaColour]); + if(manaRequired[manaColour] > manaAvailable[manaColour]){ + return 'Do not have enough: '+manaColour+' mana'; + } + } + + console.log('manaAvailable: '); + console.log(manaAvailable); + + return true; + } + + getManaTotalOf(itemKey){ + let manaTotal = {0:0, 1:0, 2:0, 3:0, 4:0}; + let manaColours = cardColours[itemKey]; + + for(let i = 0; i < cardColours[itemKey].length; i++){ + // Add one to the available mana + let colourId = manaColours[i][0]; + manaTotal[colourId] += manaColours[i][1]; // Add the cost } - return 'Do not have correct mana requirements'; + console.log('manaTotal: '); + console.log(manaTotal); + return manaTotal; } inspectCard(cardToInspect){ From aae1ed1be70f28b397a5d145ff6496aad2b7a587 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 20 Oct 2024 16:56:05 +0100 Subject: [PATCH 02/13] Fix mana tap (+ kinda multi-colour) --- public/board.js | 105 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 75 insertions(+), 30 deletions(-) diff --git a/public/board.js b/public/board.js index 2ccf13c..0fe9163 100644 --- a/public/board.js +++ b/public/board.js @@ -523,21 +523,10 @@ class Board{ 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; - } - } + // TODO: May be best to tap in canPayMana while looping reqs. and if the reqs aren't hit untap the mana that were tapped in that call? + // This atm will loop manaReq and tap. + let tapped = this.tapManaRequired(itemKey, fromPlayer); + alert('tapManaRequired: '+tapped); } } @@ -548,6 +537,61 @@ class Board{ this.drawBoard(); } + tapManaRequired(itemToPayCost, playerId){ + + // TODO: Look at combining or normalising this and canPayMana() + let manaRequired = this.getManaTotalOf(itemToPayCost); + let noManaReq = {1:0, 2:0, 3:0, 4:0}; + + // Loop all the mana + let items = this.getItems('mana', playerId, null, null); + for(let item = 0; item < items.length; item++){ + + let mana = items[item]; + + if(this.isTapped(mana)){ + continue; + } + + + // TODO: do better. + let manaType = null; // TODO: Will use the highest mana req as it's colour for now + let manaColours = cardColours[mana]; + for(let i = 0; i < manaColours.length; i++){ + // Set mana colour for card if there isn't one + if(manaType == null){ manaType = manaColours[i]; } + // Check each other colour, use the highest cost colour + // as the colour type for this specific mana + // TODO: Do better, and nicer, manaType in DB with the colour? + if(manaColours[i][1] > manaType[1]){ + manaType = manaColours[i]; + } + } + + let colourId = manaType[0]; + console.log(JSON.stringify(manaRequired)); + // Loop the requirements of the cost to pay + for (const manaColour in manaRequired) { + //console.log(manaColour+' '+manaRequired[manaColour]+', '+colourId); + // If the colour of the mana is in the requirements + // of the cost to pay, reduce the cost for that colour by + // 1 and tap the mana + if(manaColour == colourId && manaRequired[manaColour] > 0){ + // Reduce the required mana + manaRequired[colourId]--; + this.tapCard(mana); + } + } + + // End loop once mana Req are fulfilled + if(JSON.stringify(manaRequired) == JSON.stringify(noManaReq)){ + return true; + } + } + + return('tapMana could not tap correct mana'); + } + getItemKey(boardElementId, listPositionId, playerFrom){ let itemKey = this.getItems(boardElementId, playerFrom, null, listPositionId); if(itemKey.length < 1){ @@ -583,7 +627,7 @@ class Board{ // may not be needed to tap them all (if cost reduced), but they need // to have those colours available. // Setting them to 0 to start so they can be added to. Could be nicer - let manaAvailable = {0:0, 1:0, 2:0, 3:0, 4:0}; + let manaAvailable = {1:0, 2:0, 3:0, 4:0}; // TODO: Thought, maybe instead of tapping colour used, it's just if you // have the colour? May be a silly thought, but @@ -593,7 +637,7 @@ class Board{ // player check for this may need changing for "play from opp hand" etc? - let items = this.getItems('mana', player[itemToPlay], null, null); + let items = this.getItems('mana', playerId, null, null); for(let item = 0; item < items.length; item++){ // Looping the mana to check player has equal mana/colours to req. let itemKey = items[item]; @@ -630,33 +674,34 @@ class Board{ // If the manaReq is satiated by the manaAvailable then return true for (const manaColour in manaRequired) { - console.log('req'); - console.log(manaRequired[manaColour]); - console.log('av'); - console.log(manaAvailable[manaColour]); + //console.log('req'); + //console.log(manaRequired[manaColour]); + //console.log('av'); + //console.log(manaAvailable[manaColour]); if(manaRequired[manaColour] > manaAvailable[manaColour]){ return 'Do not have enough: '+manaColour+' mana'; } } - console.log('manaAvailable: '); - console.log(manaAvailable); + //console.log('manaAvailable: '); + //console.log(manaAvailable); return true; } getManaTotalOf(itemKey){ - let manaTotal = {0:0, 1:0, 2:0, 3:0, 4:0}; + let manaTotal = {1:0, 2:0, 3:0, 4:0}; let manaColours = cardColours[itemKey]; - for(let i = 0; i < cardColours[itemKey].length; i++){ + console.log(manaColours.length); + for(let i = 0; i < manaColours.length; i++){ // Add one to the available mana let colourId = manaColours[i][0]; manaTotal[colourId] += manaColours[i][1]; // Add the cost } - console.log('manaTotal: '); - console.log(manaTotal); + //console.log('manaTotal: '); + //console.log(manaTotal); return manaTotal; } @@ -913,11 +958,11 @@ function loadBoard(data) { // TODO: JANK IN, CHANGE CODE TO USE NEW ARRAY!! // Temp jank, set colour to first colour req. for(let i = 0; i < itemCount; i++){ - console.log(itemCount); - console.log(cardColours[itemCount]); + //console.log(itemCount); + //console.log(cardColours[itemCount]); // after && to check if there is a colourReq record in cardColours if(cardData[i] !== undefined && i in cardColours){ // i may not have carddata, as realDeck - console.log(i); + //console.log(i); cardData[i].colour = cardColours[i][0][0]; // Colour Id of first req // Set the artwork (this would be done front-end I think) cardSprite[i] = [0,0]; From 7570729449aff1213c440240dbe03cda628b6299 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 20 Oct 2024 17:06:18 +0100 Subject: [PATCH 03/13] Create temp function for jank 'getPrimaryColour' --- public/board.js | 59 ++++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/public/board.js b/public/board.js index 0fe9163..e6e4591 100644 --- a/public/board.js +++ b/public/board.js @@ -553,22 +553,8 @@ class Board{ continue; } + let colourId = this.tempGetPrimaryManaOfCard(mana); - // TODO: do better. - let manaType = null; // TODO: Will use the highest mana req as it's colour for now - let manaColours = cardColours[mana]; - for(let i = 0; i < manaColours.length; i++){ - // Set mana colour for card if there isn't one - if(manaType == null){ manaType = manaColours[i]; } - // Check each other colour, use the highest cost colour - // as the colour type for this specific mana - // TODO: Do better, and nicer, manaType in DB with the colour? - if(manaColours[i][1] > manaType[1]){ - manaType = manaColours[i]; - } - } - - let colourId = manaType[0]; console.log(JSON.stringify(manaRequired)); // Loop the requirements of the cost to pay for (const manaColour in manaRequired) { @@ -647,6 +633,29 @@ class Board{ continue; } + let colourId = this.tempGetPrimaryManaOfCard(itemKey); + manaAvailable[colourId] += 1; + + } + + // If the manaReq is satiated by the manaAvailable then return true + for (const manaColour in manaRequired) { + //console.log('req'); + //console.log(manaRequired[manaColour]); + //console.log('av'); + //console.log(manaAvailable[manaColour]); + if(manaRequired[manaColour] > manaAvailable[manaColour]){ + return 'Do not have enough: '+manaColour+' mana'; + } + } + + //console.log('manaAvailable: '); + //console.log(manaAvailable); + + return true; + } + + tempGetPrimaryManaOfCard(targetCard){ // Loop the mana card's colours // can be multi-coloured, and can be used as diff costs @@ -657,7 +666,7 @@ class Board{ // cards aren't all those when in mana (ie. 6 colour decks can't play // everything all the time) let manaType = null; // TODO: Will use the highest mana req as it's colour for now - let manaColours = cardColours[itemKey]; + let manaColours = cardColours[targetCard]; for(let i = 0; i < manaColours.length; i++){ // Set mana colour for card if there isn't one if(manaType == null){ manaType = manaColours[i]; } @@ -669,24 +678,8 @@ class Board{ } } let colourId = manaType[0]; - manaAvailable[colourId] += 1; - } + return colourId; - // If the manaReq is satiated by the manaAvailable then return true - for (const manaColour in manaRequired) { - //console.log('req'); - //console.log(manaRequired[manaColour]); - //console.log('av'); - //console.log(manaAvailable[manaColour]); - if(manaRequired[manaColour] > manaAvailable[manaColour]){ - return 'Do not have enough: '+manaColour+' mana'; - } - } - - //console.log('manaAvailable: '); - //console.log(manaAvailable); - - return true; } getManaTotalOf(itemKey){ From b663232ebf650a041cbbdb7c248a95e578b61b69 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 20 Oct 2024 18:09:07 +0100 Subject: [PATCH 04/13] Add to flipCard(), and flip mana (down) on play --- public/board.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/public/board.js b/public/board.js index e6e4591..8e85919 100644 --- a/public/board.js +++ b/public/board.js @@ -220,11 +220,17 @@ class Board{ } return false; } - flipCard(itemKey){ - if(cardFace[itemKey] == 1){ + flipCard(itemKey, direction = null){ + // TODO: Add a third param for 'triggerEffects', for instance + // flipping up from deck to hand, or shield to hand shouldn't trigger + // MOST TIMES + if(cardFace[itemKey] == 1 && (direction == null || direction == 0)){ cardFace[itemKey] = 0; - }else{ + return true; + } + if(cardFace[itemKey] == 0 && (direction == null || direction == 1)){ cardFace[itemKey] = 1; + return true; } // TODO:Activate any flip effects, etc. } @@ -842,7 +848,14 @@ class Board{ } playMana(fromPosition, fromElement, fromPlayer){ + // TODO: getItemKey may be the best way to normalise other function calls instead of searching for item key within certain other funcs. (such as addFromBoardElement) + let itemKey = this.getItemKey(fromElement, fromPosition, fromPlayer); + + console.log(itemKey); + // Now add to mana zone this.addFromBoardElement(fromPlayer, fromPosition, fromElement, 'mana', null, null); + // Flip the card face down (for now) TODO: just add colour atop + this.flipCard(itemKey, 0); // Face down (TODO: Change to have spec. style) } // HELPER METHODS, to simplify code-base for me in the future From 89391f5bbb446f42418b94ba83f1aa5ec87aa45f Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 20 Oct 2024 18:16:27 +0100 Subject: [PATCH 05/13] Add the tempGetCol.. to jank colour in loadBoard --- public/board.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/board.js b/public/board.js index 8e85919..e96f160 100644 --- a/public/board.js +++ b/public/board.js @@ -969,7 +969,8 @@ function loadBoard(data) { // after && to check if there is a colourReq record in cardColours if(cardData[i] !== undefined && i in cardColours){ // i may not have carddata, as realDeck //console.log(i); - cardData[i].colour = cardColours[i][0][0]; // Colour Id of first req + cardData[i].colour = board.tempGetPrimaryManaOfCard(i); + //cardData[i].colour = cardColours[i][0][0]; // Colour Id of first req // Set the artwork (this would be done front-end I think) cardSprite[i] = [0,0]; // Temp sprite set based on colour TODO: Change to set correct sprite from DB From 40e85730ba3f632e5fecb894dbdc3a3a635712fc Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 20 Oct 2024 18:24:43 +0100 Subject: [PATCH 06/13] Add the mana colour onto mana cards --- public/board.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/public/board.js b/public/board.js index e96f160..07b5288 100644 --- a/public/board.js +++ b/public/board.js @@ -213,6 +213,21 @@ class Board{ ctx.fillStyle = '#000'; ctx.fillText(deckLength, textx, texty); } + // If the item is a mana, draw the mana colour within it + // Temp solution, but works for UI and testing + if(boardElement[itemKey] == 'mana'){ + // TODO: Seperate this into a 'drawMana' or something? + let manaColour = new Shape({ + shape: 'circle', + //name: 'deckCountererer', + x: positionX + width/2, + y: positionY + height/2, + width: width*.75, + height: height*.75, + fillStyle: fill // Fill should be the card's main colour + }); + manaColour.draw(); + } } isFaceUp(itemKey){ if(cardFace[itemKey] == 1){ From 7bd0840d751fedf5cc8e6322fd93c96a9777beb6 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 20 Oct 2024 19:56:21 +0100 Subject: [PATCH 07/13] Add colourReq to card UI --- public/board.js | 71 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/public/board.js b/public/board.js index 07b5288..fc412f9 100644 --- a/public/board.js +++ b/public/board.js @@ -149,14 +149,12 @@ class Board{ if(this.isAttacking(itemKey)){border = '#C92D22';} // Set the card 'cardboard' colour based on the card colour type - let fill = null; + let fill = '#B0B0B0'; if(boardElement[itemKey] != 'realDeck'){ // TODO: Change these to isset checks instead... let colourId = cardData[itemKey].colour; if(colourId == COLOUR.white){ fill = '#EEE'; } else if(colourId == COLOUR.blue){ fill = '#0033EE'; } else if(colourId == COLOUR.red){ fill = '#ED344A'; } - }else{ - fill = '#B0B0B0'; } let name = itemKey; // Not needed really anymore, but keeping for now @@ -181,6 +179,7 @@ class Board{ if(this.isFaceUp(itemKey)){ this.addCardImage(itemKey); this.printCardDetails(itemKey); + this.printColourRequirements(itemKey); } if(!this.isFaceUp(itemKey)){ this.addCardBack(itemKey); @@ -304,6 +303,72 @@ class Board{ // TODO: CardBack/Sleeves as spritesheet like cardArt ctx.drawImage(cardBackArt, 0,0, 80,120,positionX,positionY,width,height); } + printColourRequirements(itemKey){ + // Set the size(s) + let width = size[itemKey][0]*.1; + let height = size[itemKey][1]*.1; + let positionX = position[itemKey][0] + (size[itemKey][0]*.1); + let positionY = position[itemKey][1] + (size[itemKey][0]*.2); + + + // Get all the colour reqs needed. + let colourReqs = cardColours[itemKey]; + + // Loop them all + let totalColours = 1; // How many colours the card has, for positioning + colourReqs.forEach((colour) => { + console.log('colour'); + + // Add each to the card (colour BG, and required count within it) + // TODO: Maybe building a class for each draw is bad, eh. + // TODO: Should probably change the shapes.js class into functions + // Will look into once animations, etc are in, incase classes are the way + + // TODO: change colours to have id(done), name, and hexcode as const/enum + let fill = '#B0B0B0'; + let colourId = colour[0]; + if(colourId == COLOUR.white){ fill = '#EEE'; } + else if(colourId == COLOUR.blue){ fill = '#0033EE'; } + else if(colourId == COLOUR.red){ fill = '#ED344A'; } + + // Draw the mana shape/icon + let manaColour = new Shape({ + shape: 'circle', + //name: 'deckCountererer', + x: positionX, + y: positionY + height*totalColours, + width: width, + height: height, + fillStyle: fill // Fill should be the card's main colour + }); + manaColour.draw(); + + // Draw the requirement within the shape/icon + // Make sure the text scales with card size + let fontSize = (width*10/cardWidth)*10; // 10 = baseFontSize of 10pt + // ^ calced with the width of the card overall + context.font = fontSize+"pt Arial"; + context.fillStyle = "#FFF"; + // Center the text (cost) within the shape + this.printCenterText(colour[1], positionX, positionY + height*totalColours); + // Reset context stylings + context.font = "10pt Arial"; // Reset to default + context.fillStyle = "#000"; + + // Inc totalColours in case there's more + totalColours++; + + }); + } + printCenterText(text, positionX, positionY){ + context.textAlign = 'center'; + context.textBaseline = 'middle'; + context.fillText(text, positionX, positionY); + + // Now reset the context aligns to the defaults + context.textAlign = 'left'; + context.textBaseline = 'alphabetic'; + } printCardDetails(itemKey){ let name = itemKey; // Not needed really anymore, but keeping for now let positionX = position[itemKey][0]; From 5e819bfefecada8233df520da3c1fce08686c41c Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 20 Oct 2024 20:59:33 +0100 Subject: [PATCH 08/13] Contrast the text colour for colourCosts icons --- public/board.js | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/public/board.js b/public/board.js index fc412f9..77ff5f4 100644 --- a/public/board.js +++ b/public/board.js @@ -348,7 +348,8 @@ class Board{ let fontSize = (width*10/cardWidth)*10; // 10 = baseFontSize of 10pt // ^ calced with the width of the card overall context.font = fontSize+"pt Arial"; - context.fillStyle = "#FFF"; + // Get a constrating B/W to the background and set text to that + context.fillStyle = invertColour(fill, true); // Center the text (cost) within the shape this.printCenterText(colour[1], positionX, positionY + height*totalColours); // Reset context stylings @@ -1538,3 +1539,35 @@ function echoCardsInDeck(playerId){ console.log(deckList); } +// https://stackoverflow.com/a/35970186 +function invertColour(hex, bw = true) { + // Split the hex code into individual alphanumerics + if (hex.indexOf('#') === 0) { + hex = hex.slice(1); + } + + // convert 3-digit hex to 6-digits. + if (hex.length === 3) { + hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; + } + if (hex.length !== 6) { throw new Error('Invalid HEX colour.'); } + + let r = parseInt(hex.slice(0, 2), 16), + g = parseInt(hex.slice(2, 4), 16), + b = parseInt(hex.slice(4, 6), 16); + + // Make it black/white for contrast (typical behaviour here) + if (bw) { + // https://stackoverflow.com/a/3943023/112731 + return (r * 0.299 + g * 0.587 + b * 0.114) > 186 + ? '#000000' : '#FFFFFF'; + } + + // Invert colour components + r = (255 - r).toString(16); + g = (255 - g).toString(16); + b = (255 - b).toString(16); + // Pad each with zeros and return + return "#" + padZero(r) + padZero(g) + padZero(b); +} + From 019e457808ec57cad0640572c434796610df729c Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 20 Oct 2024 21:21:38 +0100 Subject: [PATCH 09/13] Set COLOUR enum to contain more colour details --- public/board.js | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/public/board.js b/public/board.js index 77ff5f4..45e7210 100644 --- a/public/board.js +++ b/public/board.js @@ -10,9 +10,9 @@ const cardBackArt = new Image(); // Colours const COLOUR = { - 'white': 1, - 'blue': 2, - 'red': 3, + 'white':{'id': 1, 'name':'White','colour':'#EEE'}, + 'blue':{'id':2, 'name':'Blue','colour':'#0033EE'}, + 'red':{'id':3, 'name':'Red','colour':'#ED344A'}, }; // Counters to keep track of players, and boardElements, may be changed in future @@ -152,9 +152,7 @@ class Board{ let fill = '#B0B0B0'; if(boardElement[itemKey] != 'realDeck'){ // TODO: Change these to isset checks instead... let colourId = cardData[itemKey].colour; - if(colourId == COLOUR.white){ fill = '#EEE'; } - else if(colourId == COLOUR.blue){ fill = '#0033EE'; } - else if(colourId == COLOUR.red){ fill = '#ED344A'; } + fill = this.setFillByManaColour(colourId); } let name = itemKey; // Not needed really anymore, but keeping for now @@ -317,7 +315,6 @@ class Board{ // Loop them all let totalColours = 1; // How many colours the card has, for positioning colourReqs.forEach((colour) => { - console.log('colour'); // Add each to the card (colour BG, and required count within it) // TODO: Maybe building a class for each draw is bad, eh. @@ -325,11 +322,8 @@ class Board{ // Will look into once animations, etc are in, incase classes are the way // TODO: change colours to have id(done), name, and hexcode as const/enum - let fill = '#B0B0B0'; let colourId = colour[0]; - if(colourId == COLOUR.white){ fill = '#EEE'; } - else if(colourId == COLOUR.blue){ fill = '#0033EE'; } - else if(colourId == COLOUR.red){ fill = '#ED344A'; } + let fill = this.setFillByManaColour(colourId); // Draw the mana shape/icon let manaColour = new Shape({ @@ -361,6 +355,15 @@ class Board{ }); } + setFillByManaColour(colourId){ + for (const colour in COLOUR) { + if(colourId == COLOUR[colour]['id']){ + return COLOUR[colour]['colour']; // Lmao + } + } + + return '#B0B0B0'; + } printCenterText(text, positionX, positionY){ context.textAlign = 'center'; context.textBaseline = 'middle'; @@ -1056,16 +1059,16 @@ function loadBoard(data) { cardSprite[i] = [0,0]; // Temp sprite set based on colour TODO: Change to set correct sprite from DB switch (cardData[i].colour){ - case COLOUR.white: // White + case COLOUR.white.id: // White cardSprite[i] = [0,0]; break; - case COLOUR.blue: // Blue + case COLOUR.blue.id: // Blue cardSprite[i] = [0,1]; break; - case COLOUR.red: // Red + case COLOUR.red.id: // Red cardSprite[i] = [1,0]; break; - case COLOUR.green: // Green + case COLOUR.green.id: // Green cardSprite[i] = [1,1]; break; default: From fe41db49e514b8af2ecd5b65b9df8cc5ad8dce32 Mon Sep 17 00:00:00 2001 From: Nathan Date: Wed, 23 Oct 2024 09:59:21 +0100 Subject: [PATCH 10/13] Add 'manaColour' attribute/DB element Currently cards will only have one mana colour, in future need to extend the (in code) functionality to multiple, as DB is already set to allow multiple. --- cardGen.js | 43 +++++++++++++++++++++++++++++++++--- database.js | 17 ++++++++++++++ db/231024_0956_migration.sql | 14 ++++++++++++ public/board.js | 9 +++++--- 4 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 db/231024_0956_migration.sql diff --git a/cardGen.js b/cardGen.js index 17a8b98..13534e7 100644 --- a/cardGen.js +++ b/cardGen.js @@ -140,6 +140,27 @@ function getCardColourRequirement(){ }); return dPromise; } +function getCardManaColour(){ + const cPromise = new Promise((resolve, reject) => { + database.dbGetCardManaColour().then(data => { + + let manaColours = []; + + data.forEach((cardManaColour) => { + + manaColours.push({ + 'cardId': cardManaColour.cardId, + 'colourId': cardManaColour.colourId, + }); + + }); + resolve(manaColours); + + }) + .catch(err => { throw err; }) + }); + return cPromise; +} //getCardColourRequirement(); // Then effects which will have effects with parent triggers, and unit type checks // colour checks, all sorts. So will be more difficult. Basic (flight, etc) @@ -187,11 +208,12 @@ function requestDeck(itemData = null){ // Change SQL to accept for just the cards passed // Get each cards data, colourReqs, and classes - const [cards, cardClasses, cardColourRequirements] = + const [cards, cardClasses, cardColourRequirements, cardManaColours] = await Promise.all([ getCards(), getCardClasses(), getCardColourRequirement(), + getCardManaColour(), ]); // ^^^^ Classes async? Can pass the cardsIds, then loop classes, if the class cardId // matches the cardId in cards[] then push the class to cards[x].classes @@ -204,7 +226,7 @@ function requestDeck(itemData = null){ const [builtCards] = await Promise.all([ - buildCards(cards, cardClasses, cardColourRequirements), + buildCards(cards, cardClasses, cardColourRequirements, cardManaColours), // TODO: builtEffects ]); @@ -262,6 +284,7 @@ function requestDeck(itemData = null){ let cardColours = {}; // Array of req. let cardAttack = {}; // Base, Current let cardSprite = {}; // Maybe from DB? + let cardManaColour = {}; // The card colour value when played in mana zone // TODO: Set the player. For now will do this in front-end as testing currently @@ -320,6 +343,7 @@ function requestDeck(itemData = null){ cardStatus[itemCount] = null; cardFace[itemCount] = 0; // Face down by default (in deck) cardColours[itemCount] = cardData[itemCount].colourRequirements; // TODO; + cardManaColour[itemCount] = cardData[itemCount].cardManaColour; // From cardData set the base attack, and current (same when deckbuild) let atk = cardData[itemCount].atk; cardAttack[itemCount] = [atk, atk]; // Base, Current @@ -346,6 +370,7 @@ function requestDeck(itemData = null){ itemData.cardColours = cardColours; itemData.cardAttack = cardAttack; itemData.cardSprite = cardSprite; + itemData.cardManaColour = cardManaColour; // item, itemCount, deckData, cardData, boardElement //console.log(cardData); @@ -371,7 +396,7 @@ function requestDeck(itemData = null){ // point to see. For now DB, and generating is ok, as still working on it } -function buildCards(cards, cardClasses, cardColourRequirements){ +function buildCards(cards, cardClasses, cardColourRequirements, cardManaColours){ console.log(cardColourRequirements); const dPromise = new Promise((resolve, reject) => { @@ -388,6 +413,7 @@ function buildCards(cards, cardClasses, cardColourRequirements){ colour: [], cost: card.cardCost, colourRequirements: [], + cardManaColour: [], // Should probably be an object type: card.cardType, atk: card.cardAttack, rarity: card.cardRarity, @@ -436,6 +462,17 @@ function buildCards(cards, cardClasses, cardColourRequirements){ }); + // Add card mana colours (colour value when played in mana zone) + cardManaColours.forEach((manaCol) => { + + // Check the card exists (it should always, but don't want jank) + if(manaCol.cardId in builtCards){ + // Add the colours to the class array (cards can have multiple) + builtCards[manaCol.cardId].cardManaColour.push(manaCol.colourId); + } + + }); + resolve(builtCards); }); diff --git a/database.js b/database.js index 723dba7..8701abd 100644 --- a/database.js +++ b/database.js @@ -107,6 +107,22 @@ function dbGetCardColourRequirement(){ return dPromise; } +function dbGetCardManaColour(){ + // Get the classes assoc. on each card + const cPromise = new Promise((resolve, reject) => { + let sql = `SELECT + cardId + ,colourId + FROM card_mana_colour + `; + + con.query(sql, function (err, result, fields) { + if (err) { throw err; reject(new Error(err)); } + resolve(result); + }); + }); + return cPromise; +} module.exports = { connect, disconnect @@ -116,4 +132,5 @@ module.exports = { , dbGetCards , dbGetCardClasses , dbGetCardColourRequirement + , dbGetCardManaColour }; diff --git a/db/231024_0956_migration.sql b/db/231024_0956_migration.sql new file mode 100644 index 0000000..531e946 --- /dev/null +++ b/db/231024_0956_migration.sql @@ -0,0 +1,14 @@ +USE `realms_divided`; +CREATE TABLE IF NOT EXISTS `card_mana_colour` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `cardId` int(11) DEFAULT NULL, + `colourId` tinyint(4) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +INSERT INTO `card_mana_colour` (`id`, `cardId`, `colourId`) VALUES + (1, 1, 3), + (2, 2, 1), + (3, 3, 2), + (4, 4, 1), + (5, 5, 3); diff --git a/public/board.js b/public/board.js index 45e7210..481976d 100644 --- a/public/board.js +++ b/public/board.js @@ -39,6 +39,7 @@ let deckIn = {}; // NEW, may be used, for now player substitute let deckData = {}; let cardAttack = {}; // TODO: add to the logic let cardColours = {}; +let cardManaColour = {}; let inEvent = null; // To disable drawing each time something changes @@ -213,6 +214,7 @@ class Board{ // If the item is a mana, draw the mana colour within it // Temp solution, but works for UI and testing if(boardElement[itemKey] == 'mana'){ + let manaFill = this.setFillByManaColour(cardManaColour[itemKey][0]); // TODO: Seperate this into a 'drawMana' or something? let manaColour = new Shape({ shape: 'circle', @@ -221,7 +223,7 @@ class Board{ y: positionY + height/2, width: width*.75, height: height*.75, - fillStyle: fill // Fill should be the card's main colour + fillStyle: manaFill // Fill should be the card's main colour }); manaColour.draw(); } @@ -643,7 +645,7 @@ class Board{ continue; } - let colourId = this.tempGetPrimaryManaOfCard(mana); + let colourId = cardManaColour[mana][0]; console.log(JSON.stringify(manaRequired)); // Loop the requirements of the cost to pay @@ -723,7 +725,7 @@ class Board{ continue; } - let colourId = this.tempGetPrimaryManaOfCard(itemKey); + let colourId = cardManaColour[itemKey][0]; manaAvailable[colourId] += 1; } @@ -1044,6 +1046,7 @@ function loadBoard(data) { deckData = data.deckData; cardAttack = data.cardAttack; // TODO: add to the logic cardColours = data.cardColours; + cardManaColour = data.cardManaColour; // TODO: JANK IN, CHANGE CODE TO USE NEW ARRAY!! // Temp jank, set colour to first colour req. From bd465c5baabf4d0681142efd089ec10eb34afcc7 Mon Sep 17 00:00:00 2001 From: Nathan Date: Wed, 23 Oct 2024 11:14:52 +0100 Subject: [PATCH 11/13] Add gradient fill to multi-mana cards --- public/board.js | 57 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/public/board.js b/public/board.js index 481976d..417f068 100644 --- a/public/board.js +++ b/public/board.js @@ -140,6 +140,50 @@ class Board{ } } + setCardFill(itemKey){ + + let fill = '#B0B0B0'; + + let coloursOfCard = cardColours[itemKey]; + if(coloursOfCard.length > 1){ + + // Create a gradient for the card colours + // x-start,y-start,x-end,y-end + const grad=ctx.createLinearGradient( + position[itemKey][0], + 0, //position[itemKey][1], + position[itemKey][0] + size[itemKey][0], + 0, //position[itemKey][1] + size[itemKey][1] + ); + + for(let i = 0; i < coloursOfCard.length; i++){ + + let gradientPos = 0; + if(coloursOfCard.length == i){ + gradientPos = 1; + }else{ + // Colour stops from 0..1 (0 to 100% along) + // If 4, first is 0, second is 100/3 * 1 = 33.33% + // 0,33,66,100. Need last to always be 100 (1) + gradientPos = (coloursOfCard.length - 1)*i; + } + + // TODO: Make new array ensuring colours are ordered by highest + // cost. This will do as it adds the colours, but in future + grad.addColorStop(gradientPos, this.setFillByManaColour(cardColours[itemKey][i][0])); + + } + + fill = grad; + }else{ + // Set to a normal fill of the first (only) colour + fill = this.setFillByManaColour(cardColours[itemKey][0][0]); + } + + return fill; + + } + printCardToCanvas(itemKey){ // If the itemKey has cardData, position, size, and boardElement we can draw it // TODO: Add a check for error handling @@ -149,19 +193,18 @@ class Board{ 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 = '#B0B0B0'; - if(boardElement[itemKey] != 'realDeck'){ // TODO: Change these to isset checks instead... - let colourId = cardData[itemKey].colour; - fill = this.setFillByManaColour(colourId); - } - 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]; + // Set the card 'cardboard' colour based on the card colour type + let fill = '#B0B0B0'; + if(boardElement[itemKey] != 'realDeck'){ // TODO: Change these to isset checks instead... + fill = this.setCardFill(itemKey); + } + // Draw the card shape itself let shape = new Shape({ name: name, From 8ebabeaa9ceabdb08b99781d70d9ff8435eb1a4e Mon Sep 17 00:00:00 2001 From: Nathan Date: Wed, 23 Oct 2024 14:48:08 +0100 Subject: [PATCH 12/13] Alter mana tap allow 2+cost with only 1 manareq --- public/board.js | 95 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 83 insertions(+), 12 deletions(-) diff --git a/public/board.js b/public/board.js index 417f068..4e5a2b2 100644 --- a/public/board.js +++ b/public/board.js @@ -661,7 +661,10 @@ class Board{ // TODO: May be best to tap in canPayMana while looping reqs. and if the reqs aren't hit untap the mana that were tapped in that call? // This atm will loop manaReq and tap. let tapped = this.tapManaRequired(itemKey, fromPlayer); - alert('tapManaRequired: '+tapped); + if(tapped != true){ + alert('tapManaRequired: '+tapped); + return false; + } } } @@ -677,6 +680,7 @@ class Board{ // TODO: Look at combining or normalising this and canPayMana() let manaRequired = this.getManaTotalOf(itemToPayCost); let noManaReq = {1:0, 2:0, 3:0, 4:0}; + let manaToTap = []; // Loop all the mana let items = this.getItems('mana', playerId, null, null); @@ -684,33 +688,98 @@ class Board{ let mana = items[item]; - if(this.isTapped(mana)){ + if(this.isTapped(mana) || this.isSelected(mana)){ continue; } let colourId = cardManaColour[mana][0]; - console.log(JSON.stringify(manaRequired)); + console.log(JSON.stringify(manaRequired[0])); // Loop the requirements of the cost to pay - for (const manaColour in manaRequired) { + for (const manaColour in manaRequired[0]) { //console.log(manaColour+' '+manaRequired[manaColour]+', '+colourId); // If the colour of the mana is in the requirements // of the cost to pay, reduce the cost for that colour by // 1 and tap the mana - if(manaColour == colourId && manaRequired[manaColour] > 0){ + if(manaColour == colourId && manaRequired[0][manaColour] > 0){ // Reduce the required mana - manaRequired[colourId]--; - this.tapCard(mana); + manaRequired[0][colourId]--; + manaToTap.push(mana); + this.selectCard(mana); // Make selected so that we know to tap } } // End loop once mana Req are fulfilled - if(JSON.stringify(manaRequired) == JSON.stringify(noManaReq)){ - return true; + if(JSON.stringify(manaRequired[0]) == JSON.stringify(noManaReq)){ + break; + } + } + + // Now all the req. mana colours are tapped, check if the cost requires more + // For 3 cost cards that only require 1 red, two more mana (any colour) + // need to be tapped + // TODO: Better more efficiently and let user select... + let itemCostRemaining = cardData[itemToPayCost].cost - manaRequired[1]; + if(itemCostRemaining > 0){ + /* + let tapRequirement = (cardData[itemToPayCost].cost - manaRequired[1]); + alert('Tap: '+(tapRequirement)+' more mana to play'); + + // start mana tap event + */ + + // TODO: decide 100% how cards are to be played/payed for + // don't want to slam time into a mana system if it'll be nuked. + // For now, reloop and tap first available mana so that card + // payment is satiated + // Using same items from above + for(let item = 0; item < items.length; item++){ + + let mana = items[item]; + + if(this.isTapped(mana) || this.isSelected(mana)){ + continue; + } + + if(itemCostRemaining > 0){ + manaToTap.push(mana); + itemCostRemaining--; + } + } } - return('tapMana could not tap correct mana'); + if(itemCostRemaining > 0){ + return false; // Didn't find another mana to tap so cost not satiated + } + + // If the mana to tap has been satitated then tap the mana selected + manaToTap.forEach(manaId => { + this.tapCard(manaId); + }); + + // And continue with whatever we were doing + return true; + + } + + isSelected(itemKey){ + if(cardStatus[itemKey] == 'selected'){ return true; } + return false; + } + selectCard(itemKey){ + // Sets card to 'selected/targetted' to show which have been selected + if(!this.isSelected[itemKey]){ + cardStatus[itemKey] = 'selected'; + } + return 'Cannot select a selected card'; + } + deselectCard(itemKey){ + if(this.isSelected[itemKey]){ + cardStatus[itemKey] = null; + return true; + } + return 'Cannot unselect an unselected card'; } getItemKey(boardElementId, listPositionId, playerFrom){ @@ -754,7 +823,7 @@ class Board{ // have the colour? May be a silly thought, but // Loop the card to be played, and total its mana requirements - let manaRequired = this.getManaTotalOf(itemToPlay); + let manaRequired = this.getManaTotalOf(itemToPlay)[0]; // player check for this may need changing for "play from opp hand" etc? @@ -820,17 +889,19 @@ class Board{ getManaTotalOf(itemKey){ let manaTotal = {1:0, 2:0, 3:0, 4:0}; let manaColours = cardColours[itemKey]; + let totalManaColourReq = 0; console.log(manaColours.length); for(let i = 0; i < manaColours.length; i++){ // Add one to the available mana let colourId = manaColours[i][0]; manaTotal[colourId] += manaColours[i][1]; // Add the cost + totalManaColourReq += manaColours[i][1]; } //console.log('manaTotal: '); //console.log(manaTotal); - return manaTotal; + return [manaTotal, totalManaColourReq]; } inspectCard(cardToInspect){ From 5691411697a701a4c27e2badd15dd6a9d3f0a2a8 Mon Sep 17 00:00:00 2001 From: Nathan Date: Wed, 23 Oct 2024 17:46:36 +0100 Subject: [PATCH 13/13] Fix card not playing with mana cost reached --- public/board.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/public/board.js b/public/board.js index 4e5a2b2..a7c4a10 100644 --- a/public/board.js +++ b/public/board.js @@ -688,7 +688,10 @@ class Board{ let mana = items[item]; - if(this.isTapped(mana) || this.isSelected(mana)){ + // Deselect the mana at the start to ensure it's not doopid + this.deselectCard(mana); + + if(this.isTapped(mana)){ continue; } @@ -737,20 +740,21 @@ class Board{ let mana = items[item]; + if(itemCostRemaining <= 0){ + break; + } + if(this.isTapped(mana) || this.isSelected(mana)){ continue; } - if(itemCostRemaining > 0){ - manaToTap.push(mana); - itemCostRemaining--; - } + manaToTap.push(mana); } } - if(itemCostRemaining > 0){ - return false; // Didn't find another mana to tap so cost not satiated + if(cardData[itemToPayCost].cost - manaToTap.length > 0){ + return 'itemCostRemaining: '+itemCostRemaining; // Didn't find another mana to tap so cost not satiated } // If the mana to tap has been satitated then tap the mana selected