diff --git a/cardGen.js b/cardGen.js index 13534e7..9adaf11 100644 --- a/cardGen.js +++ b/cardGen.js @@ -1,6 +1,7 @@ // Need to require DB again. Apparently this is ok, as it'll // still only have one require cross project (?) const database = require('./database'); +const util = require('util') // cardClass, cardColourRequirement @@ -161,6 +162,118 @@ function getCardManaColour(){ }); return cPromise; } +// Build card effects +// TODO: Accept card Ids (array) +function buildCardEffects(effects, effectSteps, effectTriggers){ + const cPromise = new Promise((resolve, reject) => { + + let cardEffects = {}; + let effectData = {}; + + effects.forEach((effect) => { + // If card doesn't currently have an effect + if(cardEffects[effect.cardId] === undefined){ + cardEffects[effect.cardId] = []; + } + // Add the effectId to the temp cardId + cardEffects[effect.cardId].push(effect.effectId); + + // Now actually start the effect + effectData[effect.effectId]={}; + + // Add the description to new effect + effectData[effect.effectId]['description'] = effect.description; + effectData[effect.effectId]['step'] = {}; + effectData[effect.effectId]['trigger'] = {}; + }); + //console.log(cardEffects); + //console.log(effectData); + + effectSteps.forEach((step) => { + // If step doesn't exist, add step (id of DB item) + if(effectData[step.effectId]['step'][step.stepId] === undefined){ + effectData[step.effectId]['step'][step.stepId] = {}; + + // Add the step effect details + effectData[step.effectId]['step'][step.stepId] = { + // Order steps occur in, two same = 'simultaneous' + 'stepOrder': step.stepOrder, + // The hardcoded effect that will occur at step + 'basicEffectId': step.basicEffectId, + // How much/many the effect will do/trigger + 'amount': step.amount, + 'target': [], + }; + } + + // At this point there should be data in effectStep + // Add a new 'target' (each step can have many) + effectData[step.effectId]['step'][step.stepId]['target'] + .push({ + 'colourId': step.colourId, + 'typeId': step.typeId, + 'classId': step.classId, + 'passiveId': step.passiveId, + 'itemFromStep': step.itemFromStep, + }); + + }); + //console.log(util.inspect(effectData, true, 4, true)) + + effectTriggers.forEach((trigger) => { + // If trigger doesn't exist, add trigger (id of DB item) + if(effectData[trigger.effectId]['trigger'][trigger.triggerId] === undefined){ + effectData[trigger.effectId]['trigger'][trigger.triggerId] = {}; + + // Add the trigger effect details + effectData[trigger.effectId]['trigger'][trigger.triggerId] = { + 'triggerTypeId': trigger.triggerTypeId, + 'amount': trigger.amount, + 'target': [], + }; + } + + // Add a new 'target' (each trigger can have many) + effectData[trigger.effectId]['trigger'][trigger.triggerId]['target'] + .push({ + 'colourId': trigger.colourId, + 'typeId': trigger.typeId, + 'classId': trigger.classId, + 'passiveId': trigger.passiveId, + }); + }); + //console.log(util.inspect(effectData, true, 5, true)) + + resolve([cardEffects, effectData]); + + }); + return cPromise; +} + + +function getCardPassive(){ + const cPromise = new Promise((resolve, reject) => { + database.dbGetPassive().then(data => { + + let passives = []; + + data.forEach((passive) => { + + passives.push({ + 'cardId': passive.cardId, + 'passiveId': passive.passiveId, + }); + + }); + console.log(passives); + resolve(passives); + + }) + .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) @@ -208,13 +321,15 @@ function requestDeck(itemData = null){ // Change SQL to accept for just the cards passed // Get each cards data, colourReqs, and classes - const [cards, cardClasses, cardColourRequirements, cardManaColours] = + const [cards, cardClasses, cardColourRequirements, cardManaColours, cardPassives] = await Promise.all([ getCards(), getCardClasses(), getCardColourRequirement(), getCardManaColour(), + getCardPassive(), ]); + // ^^^^ 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 @@ -224,10 +339,27 @@ function requestDeck(itemData = null){ //console.info(cardClasses); //console.log(cardColourRequirements); + // Return all effect data from DB + const [effects, effectSteps, effectTriggers] = + await Promise.all([ + database.dbGetEffect(), + database.dbGetEffectStep(), + database.dbGetEffectTrigger(), + ]); + + // Build Effects + const [cardEffects] = + await Promise.all([ + buildCardEffects(effects, effectSteps, effectTriggers), + ]); + // cardEffects[0][cardId] == [array of effect IDs] + // cardEffects[1][effectId] == {object of the effect data} + //console.log(cardEffects); + + // Build the cardData (maybe do all the components here too) const [builtCards] = await Promise.all([ - buildCards(cards, cardClasses, cardColourRequirements, cardManaColours), - // TODO: builtEffects + buildCards(cards, cardClasses, cardColourRequirements, cardManaColours, cardEffects, cardPassives), ]); //console.log(builtCards); @@ -285,6 +417,10 @@ function requestDeck(itemData = null){ let cardAttack = {}; // Base, Current let cardSprite = {}; // Maybe from DB? let cardManaColour = {}; // The card colour value when played in mana zone + let cardEffect = {}; + // Passive + let flight = {}; + let reach = {}; // TODO: Set the player. For now will do this in front-end as testing currently @@ -348,6 +484,35 @@ function requestDeck(itemData = null){ let atk = cardData[itemCount].atk; cardAttack[itemCount] = [atk, atk]; // Base, Current player[itemCount] = forPlayer; // Jank TODO: actually set to correct player + + // Add the cardEffect(s) to the cardEffect component + // only if there is an effect, starting to think about + // not wasting RAM/storage, y'know + if(cardData[itemCount].effect.length > 0){ + cardEffect[itemCount] = cardData[itemCount].effect; + } + + // Add each passive + if(cardData[itemCount].passive.length > 0){ + //console.log(cardData[itemCount].passive); + for(let i = 0; i < cardData[itemCount].passive.length; i++){ + + switch (cardData[itemCount].passive[i]){ + + // Flight + case 1: + flight[itemCount] = itemCount; + break; + + // Reach + case 2: + reach[itemCount] = itemCount; + break; + + } + + } + } itemCount++; // Increment item to not overwrite @@ -371,6 +536,9 @@ function requestDeck(itemData = null){ itemData.cardAttack = cardAttack; itemData.cardSprite = cardSprite; itemData.cardManaColour = cardManaColour; + itemData.cardEffect = cardEffect; + itemData.flight = flight; + itemData.reach = reach; // item, itemCount, deckData, cardData, boardElement //console.log(cardData); @@ -396,7 +564,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, cardManaColours){ +function buildCards(cards, cardClasses, cardColourRequirements, cardManaColours, cardEffects, cardPassives){ console.log(cardColourRequirements); const dPromise = new Promise((resolve, reject) => { @@ -419,6 +587,7 @@ function buildCards(cards, cardClasses, cardColourRequirements, cardManaColours) rarity: card.cardRarity, effect: [], cardClass: [], + passive: [], }; // Give the card an easily accessible Id for compares // and to add to the cardItem being built @@ -473,6 +642,34 @@ function buildCards(cards, cardClasses, cardColourRequirements, cardManaColours) }); + // Add the card effects that have been pre-built + // Loop the cards (each with an array of effect IDs) + for (const [key] of Object.entries(cardEffects[0])) { + + // If the cardId is not in builtCards, skip + // should always be, but eh + let cardId = cardEffects[0][key]; + if(builtCards[cardId] === undefined){ continue; } + + // Loop the effects in each of the card's effect arrays + for (const [key, value] of Object.entries(cardEffects[1])) { + // Add each effect that belongs to the card + builtCards[cardId].effect.push(value); + } + + } + + // Add card mana colours (colour value when played in mana zone) + cardPassives.forEach((passive) => { + + // Check the card exists (it should always, but don't want jank) + if(passive.cardId in builtCards){ + // Add the colours to the class array (cards can have multiple) + builtCards[passive.cardId]['passive'].push(passive.passiveId); + } + + }); + resolve(builtCards); }); diff --git a/database.js b/database.js index 8701abd..8f89c93 100644 --- a/database.js +++ b/database.js @@ -124,6 +124,104 @@ function dbGetCardManaColour(){ return cPromise; } +// Effect stuff +function dbGetEffect(){ + const ePromise = new Promise((resolve, reject) => { + let sql = `SELECT + cardId + ,effectId + ,description + FROM card_effect + + INNER JOIN effect + ON effect.id = card_effect.effectId + `; + + con.query(sql, function (err, result, fields) { + if (err) { throw err; reject(new Error(err)); } + resolve(result); + }); + }); + return ePromise; +} +function dbGetEffectStep(){ + const ePromise = new Promise((resolve, reject) => { + let sql = `SELECT + effectId, + effect_step.id AS stepId, + stepOrder, + basicEffectId, + amount, + colourId, + typeId, + classId, + passiveId, + itemFromStep + FROM effect_step + + LEFT JOIN -- May not be a target? + effect_step_target + ON effect_step_target.effectStep = effect_step.id + `; + + con.query(sql, function (err, result, fields) { + if (err) { throw err; reject(new Error(err)); } + resolve(result); + }); + }); + return ePromise; +} +// Effect Trigger stuff +function dbGetEffectTrigger(){ + const ePromise = new Promise((resolve, reject) => { + let sql = `SELECT + effect_trigger.id AS triggerId, + cardId, + effectId, + triggerTypeId, + amount, + colourId, + typeId, + classId, + passiveId + + FROM effect_trigger + + INNER JOIN card_effect + ON card_effect.effectId = effect_trigger.cardEffectId + INNER JOIN trigger_type + ON trigger_type.id = effect_trigger.triggerTypeId + + LEFT JOIN -- May not be a target + effect_trigger_target + ON effect_trigger_target.effectTriggerId = effect_trigger.triggerTypeId + `; + + con.query(sql, function (err, result, fields) { + if (err) { throw err; reject(new Error(err)); } + resolve(result); + }); + }); + return ePromise; +} + +// Passive stuff +function dbGetPassive(){ + const pPromise = new Promise((resolve, reject) => { + let sql = `SELECT + cardId + ,passiveId + FROM card_passive + `; + + con.query(sql, function (err, result, fields) { + if (err) { throw err; reject(new Error(err)); } + resolve(result); + }); + }); + return pPromise; +} + module.exports = { connect, disconnect // Testing, and trailing @@ -133,4 +231,8 @@ module.exports = { , dbGetCardClasses , dbGetCardColourRequirement , dbGetCardManaColour + , dbGetEffect + , dbGetEffectStep + , dbGetEffectTrigger + , dbGetPassive }; diff --git a/db/241024_2106_migration.sql b/db/241024_2106_migration.sql new file mode 100644 index 0000000..3de6810 --- /dev/null +++ b/db/241024_2106_migration.sql @@ -0,0 +1,124 @@ +CREATE TABLE IF NOT EXISTS `basic_effect` ( + `id` smallint(6) NOT NULL AUTO_INCREMENT, + `effectName` tinytext DEFAULT NULL, + `effectDescription` varchar(250) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +INSERT INTO `basic_effect` (`id`, `effectName`, `effectDescription`) VALUES + (1, 'Equip', 'Add this cards attack, and effect(s) to another'), + (2, 'Heal', 'Untap X shield(s)'), + (3, 'Hurt', 'Deal X damage to target unit, this combat'), + (4, 'Recruit', 'Play from Hand'), + (5, 'Give Flight', 'Give a unit [Flight]'); + + +DROP TABLE `card_effect`; +CREATE TABLE IF NOT EXISTS `card_effect` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `cardId` int(11) DEFAULT NULL, + `effectId` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +INSERT INTO `card_effect` (`id`, `cardId`, `effectId`) VALUES + (1, 1, 1); + + +CREATE TABLE IF NOT EXISTS `card_passive` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `cardId` int(11) DEFAULT NULL, + `passiveId` tinyint(4) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + +DROP TABLE `effect`; +CREATE TABLE IF NOT EXISTS `effect` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `description` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +INSERT INTO `effect` (`id`, `description`) VALUES + (1, '(Tap and Pay 1 Red): [Recruit] a [Red][Orc] unit; Give it [Flight] this turn.'); + + +CREATE TABLE IF NOT EXISTS `effect_step` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `effectId` int(11) DEFAULT NULL, + `stepOrder` tinyint(4) DEFAULT NULL, + `basicEffectId` tinyint(4) DEFAULT NULL, + `amount` smallint(6) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +INSERT INTO `effect_step` (`id`, `effectId`, `stepOrder`, `basicEffectId`, `amount`) VALUES + (1, 1, 1, 4, 1), + (2, 1, 2, 5, 1); + + +CREATE TABLE IF NOT EXISTS `effect_step_target` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `effectStep` int(11) DEFAULT NULL, + `colourId` tinyint(4) DEFAULT NULL, + `typeId` tinyint(4) DEFAULT NULL, + `classId` tinyint(4) DEFAULT NULL, + `passiveId` tinyint(4) DEFAULT NULL, + `itemFromStep` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +INSERT INTO `effect_step_target` (`id`, `effectStep`, `colourId`, `typeId`, `classId`, `passiveId`, `itemFromStep`) VALUES + (1, 1, 3, 1, 5, NULL, NULL), + (2, 2, NULL, NULL, NULL, NULL, 1); + + +CREATE TABLE IF NOT EXISTS `effect_trigger` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `triggerTypeId` int(11) DEFAULT NULL, + `cardEffectId` int(11) DEFAULT NULL, + `amount` smallint(6) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +INSERT INTO `effect_trigger` (`id`, `triggerTypeId`, `cardEffectId`, `amount`) VALUES + (1, 1, 1, NULL), + (2, 2, 1, 1); + + +CREATE TABLE IF NOT EXISTS `effect_trigger_target` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `effectTriggerId` int(11) DEFAULT NULL, + `colourId` tinyint(4) DEFAULT NULL, + `typeId` tinyint(4) DEFAULT NULL, + `classId` tinyint(4) DEFAULT NULL, + `passiveId` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +INSERT INTO `effect_trigger_target` (`id`, `effectTriggerId`, `colourId`, `typeId`, `classId`, `passiveId`) VALUES + (1, 2, 3, NULL, NULL, NULL); + + +CREATE TABLE IF NOT EXISTS `passive` ( + `id` tinyint(4) NOT NULL AUTO_INCREMENT, + `passiveName` varchar(50) DEFAULT NULL, + `passiveDescription` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +INSERT INTO `passive` (`id`, `passiveName`, `passiveDescription`) VALUES + (1, 'Flight', 'Ignore taunt, unattackable by non-[Flight] units'), + (2, 'Reach', 'Can attack [Flight] units'); + + +CREATE TABLE IF NOT EXISTS `trigger_type` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(50) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +INSERT INTO `trigger_type` (`id`, `name`) VALUES + (1, 'Tap'), + (2, 'Pay'); diff --git a/db/281024_2036_migration.sql b/db/281024_2036_migration.sql new file mode 100644 index 0000000..5b5b09e --- /dev/null +++ b/db/281024_2036_migration.sql @@ -0,0 +1,3 @@ +INSERT INTO `card_passive` (`id`, `cardId`, `passiveId`) VALUES (1, 1, 1); +INSERT INTO `card_passive` (`id`, `cardId`, `passiveId`) VALUES (2, 5, 2); + diff --git a/db/281024_2257_migration.sql b/db/281024_2257_migration.sql new file mode 100644 index 0000000..508c0e9 --- /dev/null +++ b/db/281024_2257_migration.sql @@ -0,0 +1,2 @@ +INSERT INTO `passive` (`id`, `passiveName`, `passiveDescription`) VALUES (3, 'Taunt', 'Must be targetted by attacks'); + diff --git a/public/board.js b/public/board.js index b2d9a75..e3c0d4f 100644 --- a/public/board.js +++ b/public/board.js @@ -40,6 +40,7 @@ let deckData = {}; let cardAttack = {}; // TODO: add to the logic let cardColours = {}; let cardManaColour = {}; +let cardEffect = {}; let inEvent = null; // To disable drawing each time something changes @@ -215,6 +216,10 @@ class Board{ fillStyle: fill, strokeStyle: border }); + // Add a dropshadow to flight cards (they're flyin) + if(flight[itemKey]){ + shape.setShadow(true); + } shape.draw(); // Draw the card face-up @@ -222,6 +227,7 @@ class Board{ this.addCardImage(itemKey); this.printCardDetails(itemKey); this.printColourRequirements(itemKey); + this.printCardPassives(itemKey); } if(!this.isFaceUp(itemKey)){ this.addCardBack(itemKey); @@ -346,6 +352,27 @@ class Board{ // TODO: CardBack/Sleeves as spritesheet like cardArt ctx.drawImage(cardBackArt, 0,0, 80,120,positionX,positionY,width,height); } + // Check each passive, if the card has it, add the 'icon' to display it. + printCardPassives(itemKey){ + + let passiveCount = 0; + + let positionX = position[itemKey][0]; + let positionY = position[itemKey][1] - 10; + + if(itemKey in flight){ + this.printCenterText('F', positionX + (10*passiveCount), positionY); + passiveCount++; + } + if(itemKey in reach){ + this.printCenterText('R', positionX + (10*passiveCount), positionY); + passiveCount++; + } + if(itemKey in taunt){ + this.printCenterText('T', positionX + (10*passiveCount), positionY); + passiveCount++; + } + } printColourRequirements(itemKey){ // Set the size(s) let width = size[itemKey][0]*.1; @@ -628,6 +655,34 @@ class Board{ } } + playRecruitedCard(player, fromPositionInHand){ + + // Check there's space on the board/mana zone/shield/etc + if(!this.hasSpaceInBoardElement('board', player)){ + alert('No space on board'); + return false; + } + + // Summon card to board from... + this.summonCard(player, fromPositionInHand, 'hand', player); + + // TODO: Check triggers for 'when X recruits' and add to queue + + this.drawBoard(); + + } + + summonCard(fromPlayer, positionFrom, fromElement, toPlayer){ + + // Summon card to board from... + this.addFromBoardElement(fromPlayer, positionFrom, fromElement, 'board', null, toPlayer); + + // TODO: Check triggers on 'when X summons'/'when a X is summoned' and add to queue + + this.drawBoard(); + + } + // Currently only functionality in hand playCardToBoard(positionFrom, fromElement, toElement, fromPlayer, toPlayer = null, cardsToPlay = 1){ @@ -668,17 +723,21 @@ class Board{ } } - // Move from player0, position 0 (top) of deck, to hand, to pos(null/auto) for toPlayer - this.addFromBoardElement(fromPlayer, positionFrom, fromElement, toElement, null, toPlayer); + this.summonCard(fromPlayer, positionFrom, fromElement, toPlayer); } this.drawBoard(); } - tapManaRequired(itemToPayCost, playerId){ + // TODO: Make to check mana, and actually do it. + // also make work for effects + tapManaRequired(itemToPayCost, playerId, checkOnly = false, effectCosts = null){ // TODO: Look at combining or normalising this and canPayMana() - let manaRequired = this.getManaTotalOf(itemToPayCost); + let manaRequired = []; + if(effectCosts != null){ manaRequired = effectCosts; } + else{ manaRequired = this.getManaTotalOf(itemToPayCost); } + let noManaReq = {1:0, 2:0, 3:0, 4:0}; let manaToTap = []; @@ -700,7 +759,6 @@ class Board{ console.log(JSON.stringify(manaRequired[0])); // Loop the requirements of the cost to pay 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 @@ -722,17 +780,25 @@ class Board{ // 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'); + let itemCostRemaining = 0; + let itemCost = 0; + if(itemToPayCost !== null){ + itemCostRemaining = cardData[itemToPayCost].cost - manaRequired[1]; + itemCost = cardData[itemToPayCost].cost; + } + else if(effectCosts !== null){ + itemCostRemaining = manaRequired[1]; + itemCost = manaRequired[1]; + } - // start mana tap event - */ + if(itemCostRemaining > 0){ // 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. + if(items.length < itemCostRemaining){ + return false; + } + // For now, reloop and tap first available mana so that card // payment is satiated // Using same items from above @@ -749,18 +815,21 @@ class Board{ } manaToTap.push(mana); + itemCostRemaining--; // TODO: ?????? } } - if(cardData[itemToPayCost].cost - manaToTap.length > 0){ + if(itemCost - 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 - manaToTap.forEach(manaId => { - this.tapCard(manaId); - }); + if(checkOnly == false){ // Tap the mana if this isn't a check + manaToTap.forEach(manaId => { + this.tapCard(manaId); + }); + } // And continue with whatever we were doing return true; @@ -976,6 +1045,12 @@ class Board{ let atkAttacker = this.attackOf(itemAttacking); let atkDefender = this.attackOf(itemDefending); + // Check if the attack can target the defender + if(!this.canAttackDefender(itemAttacking, itemDefending)){ + alert('Cannot target card.'); + break; + } + // Does Attacker kill Defender if(atkDefender <= atkAttacker){ this.sendToGrave(itemDefending); @@ -993,6 +1068,13 @@ class Board{ break; case 'shield': + + // Check shield can be targetted (not defended by taunt/block unit) + if(!this.canAttackDirect(itemAttacking, player[itemDefending])){ + alert('Cannot attack shield for some reason'); + break; + } + // If the shield is tapped 'destroy' it if(this.isTapped(itemDefending)){ if(!this.destroyShield(itemDefending)){ @@ -1012,6 +1094,58 @@ class Board{ this.drawBoard(); } + canAttackDefender(itemAttacking, itemDefending){ + + // Currently all there is is that flight cannot + // be attacked by anything but flight and reach + + // If defender has flight + if(flight[itemDefending]){ + // And attack doesn't have either flight or reach + if(flight[itemAttacking] === undefined && reach[itemAttacking] === undefined){ + return false; + } + } + + return true; + + + } + canAttackDirect(itemAttacking, playerDefending){ + + // Defender must not be tapped, as you can ignore tapped units + let itemsToBlock = this.getItems('board', playerDefending, null, null); + for(let item = 0; item < itemsToBlock.length; item++){ + + let defender = itemsToBlock[item]; + + // Defender cannot block if tapped + if(this.isTapped(defender)){ + continue; + } + + // If the defender doesn't have taunt, direct attacks can occur + if(taunt[defender] == undefined){ + continue; + } + + // If the attacked doesn't have flight (or another means of bypassing taunt) + // it can't attack direct + if(!flight[itemAttacking]){ + return false; + } + + // If the unitAttacking has flight, it can be blocked by a taunt+flight + // or giant+flight + if(flight[itemAttacking] && flight[defender]){ + return false; + } + + } + + return true; + + } attackOf(itemKey){ // TODO: Change this to ECSey element when added return cardData[itemKey]; @@ -1169,6 +1303,11 @@ function loadBoard(data) { cardAttack = data.cardAttack; // TODO: add to the logic cardColours = data.cardColours; cardManaColour = data.cardManaColour; + cardEffect = data.cardEffect; + + // Passives + flight = data.flight; + reach = data.reach; // TODO: JANK IN, CHANGE CODE TO USE NEW ARRAY!! // Temp jank, set colour to first colour req. @@ -1243,6 +1382,10 @@ canvas.addEventListener('contextmenu', function(event) { if(itemKey in size && itemKey in position){ // Compare the event XY position to the item if(clickableCheck(x,y,itemKey)){ + console.log('itemId: '+itemKey); + document.getElementById('effectTargetId').value = itemKey; + document.getElementById('triggerTargetId').value = itemKey; + debugGetCardEffects(itemKey); // Only want to happen once (for now) // Maybe in future add to hand would trigger another event if there's an effect? @@ -1549,6 +1692,10 @@ function calculateItemSizePosition(itemKey){ if(itemPlayer == 0 && itemElement == 'board'){ positionX = canvas.width/2 - (cardWidth * (itemListLength - (i+1)) - (cardMargin * (i+1))); positionY = canvas.height - cardHeight-30-(cardHeight); + // Move up to denote 'Flight' keyword + if(flight[itemKey]){ + positionY-=10; + } width = cardWidth; height = cardHeight; } @@ -1644,7 +1791,8 @@ function printECSData(items){ 'deckData: '+deckData[itemKey]+"\n"+ 'cardAttack: '+cardAttack[itemKey]+"\n"+ 'cardColours: '+cardColours[itemKey]+"\n"+ - 'cardManaColour: '+cardManaColour[itemKey] + 'cardManaColour: '+cardManaColour[itemKey]+"\n"+ + 'cardEffect: '+cardEffect[itemKey] ); } } diff --git a/public/debug.js b/public/debug.js new file mode 100644 index 0000000..a71caf4 --- /dev/null +++ b/public/debug.js @@ -0,0 +1,207 @@ +// For front-end debugging +// Anything to be tested that would otherwise need server logs, etc. +// should go here + +function debugEffect(){ + + let damageAmount = document.getElementById("effectDamageAmount").value; + if(damageAmount == ""){ damageAmount = null; } + + let targetId = document.getElementById("effectTargetId").value; + if(targetId == ""){ targetId = null; } + + let targetId2 = document.getElementById("effectTargetId2").value; + if(targetId2 == ""){ targetId2 = null; } + + let targetPlayer = document.getElementById("effectTargetPlayer").value; + if(targetPlayer == ""){ targetPlayer = null; } + + let effectAddRemove = document.getElementById("effectAddRemove").value; + if(effectAddRemove == ""){ effectAddRemove = null; } + + let effect = document.getElementById("effect").value; + if(effect == ""){ effect = null; } + + debugEffectFunction(damageAmount, targetId, targetId2, targetPlayer, effectAddRemove, effect); + +} + +function debugEffectFunction(damageAmount = null, targetId = null, targetId2 = null, targetPlayer = null, effectAddRemove = null, effect = null){ + + if(effect == 'hurt'){ + hurt(damageAmount, targetId, targetPlayer); + } + if(effect == 'heal'){ + heal(damageAmount, targetPlayer); + } + if(effect == 'flight'){ + console.log(targetId+' Flight: '+flight[targetId]); + + console.log(effectAddRemove); + + if(effectAddRemove == 'remove'){ + removeFlight(targetId); + }else{ + giveFlight(targetId); + } + + console.log(targetId+' Flight: '+flight[targetId]); + } + if(effect == 'reach'){ + console.log(targetId+' Reach: '+reach[targetId]); + + console.log(effectAddRemove); + + if(effectAddRemove == 'remove'){ + removeReach(targetId); + }else{ + giveReach(targetId); + } + + console.log(targetId+' Reach: '+reach[targetId]); + } + if(effect == 'taunt'){ + console.log(targetId+' Taunt: '+taunt[targetId]); + + console.log(effectAddRemove); + + if(effectAddRemove == 'remove'){ + removeTaunt(targetId); + }else{ + giveTaunt(targetId); + } + + console.log(targetId+' Taunt: '+reach[targetId]); + } + if(effect == 'draw'){ + drawCard(damageAmount, targetPlayer); + } + if(effect == 'equip'){} + + board.drawBoard(); +} + + +function debugTrigger(){ + let targetId = document.getElementById("triggerTargetId").value; + if(targetId == ""){ targetId = null; } + + let trigger = document.getElementById("trigger").value; + if(trigger == ""){ trigger = null; } + + let triggerAmount = document.getElementById("triggerAmount").value; + if(triggerAmount == ""){ triggerAmount = null; } + + debugTriggerFunction(targetId, trigger, triggerAmount); +} +function debugTriggerFunction(targetId = null, trigger = null, triggerAmount = null){ + + if(targetId == null){ return false; } + + if(trigger == 'tap'){ + triggerTap(targetId); + } + if(trigger == 'pay'){ + triggerPay(triggerAmount); + } + + board.drawBoard(); +} + +// Builds console log for card effect (inc. +// all triggers, etc) +function debugGetCardEffects(itemKey){ + + let effectData = cardEffect[itemKey]; + console.log(effectData); + if(effectData === undefined){ return false; } + + effectData.forEach((effect, effectIndex) => { + + console.log('--- Effect '+ effectIndex +' ---'); + console.log(effect['description']); + + // Loop the triggers + for (const [key, value] of Object.entries(effect['trigger'])) { + + console.log('--- Trigger ---'); + let effectTrigger = effect['trigger'][key]; + console.log(triggerTypes[effectTrigger['triggerTypeId']]); + + console.log('--- Trigger Amount ---'); + console.log(effectTrigger['amount']); + + // Loop targets for said trigger + effectTrigger['target'].forEach((effectTriggerTarget) => { + console.log('--- Trigger Target ---'); + console.log(effectTriggerTarget.classId); + console.log(effectTriggerTarget.colourId); + console.log(effectTriggerTarget.passiveId); + console.log(effectTriggerTarget.typeId); + }); + } + + // Loop the effects + for (const [key, value] of Object.entries(effect['step'])) { + // amoutn, basicEffectId, stepOrder, target (also itemfromstep) + console.log(effect['step'][key]); + + console.log('--- Effect Step ---'); + let effectStep = effect['step'][key]; + console.log(basicEffects[effectStep['basicEffectId']]); + + console.log('--- Effect Step Amount ---'); + console.log(effectStep['amount']); + + // Loop targets for effectStep + effectStep['target'].forEach((effectStepTarget) => { + console.log('--- Effect Step Target ---'); + console.log(effectStepTarget.classId); + console.log(effectStepTarget.colourId); + console.log(effectStepTarget.passiveId); + console.log(effectStepTarget.typeId); + console.log(effectStepTarget.itemFromStep); + }); + + } + + }); + +} + +function debugEffectCanTrigger(){ + + let ecTriggerTargetId = document.getElementById("ecTriggerTargetId").value; + if(ecTriggerTargetId == ""){ ecTriggerTargetId = null; } + + let ecTriggerIndex = document.getElementById("ecTriggerIndex").value; + if(ecTriggerIndex == ""){ ecTriggerIndex = 0; } + + let ecDoTrigger = document.getElementById("ecDoTrigger").value; + if(ecDoTrigger == ""){ ecDoTrigger = 0; } + + if(doEffectTriggers(ecTriggerTargetId, ecTriggerIndex, true) != true){ + console.log('Effect cannot be triggered'); + //queueEffect(ecTriggerTargetId, ecTriggerIndex); + //doNextInQueue(); + //loopTriggerQueue(); + return false; + } + + console.log('Effect CAN be triggered'); + + if(ecDoTrigger){ + // Do everything needed in triggers + doEffectTriggers(ecTriggerTargetId, ecTriggerIndex); + + // Then queue the effects to happen (queued so they can be chained/countered) + queueEffect(ecTriggerTargetId, ecTriggerIndex); + + // Do all effects in queue (for debug), in actual will do one, then allow chain triggers, etc. + loopTriggerQueue(); + } + + board.drawBoard(); + +} + diff --git a/public/effect.js b/public/effect.js new file mode 100644 index 0000000..beaa3be --- /dev/null +++ b/public/effect.js @@ -0,0 +1,680 @@ +// Theorising, if this is what's wanted then will need doing for everything +// not just in effects. eg. 'attack', 'effect1p1', 'flip', yadda yadda +let triggerQueue = []; +let triggerId = 1; // So any other effects, etc. queued for a destroyed card can be removed at once +let triggerDone = []; // The triggers that have completed +let triggerQueueTargets = []; // Whatever was targetted by the effect, etc. in triggerQueue (for ref by effectStep, etc) + +// Passive effects (just does stuff) +let flight = {}; +let reach = {}; +let taunt = {}; +let equipped = {}; // Entity x has [a,b,c] equipped to it + + +// Events (when these occur check if this is part of an effect trigger) +// startOfGame, startOfTurn, endOfTurn +// cardSummoned, cardRecruited, effectTriggered +// etc. + + +// Trigger types +const triggerTypes = { + 'tap': 1, + 'pay': 2, +}; +// Basic effects +// TODO: Pull display name/description from DB? +const basicEffects = { + 1: 'Equip', + 2: 'Heal', + 3: 'Hurt', + 4: 'Recruit', + 5: 'Give Flight', + 6: 'Taunt', +}; + + +// Actives to add passives +function giveFlight(card){ + flight[card] = true; +} +function removeFlight(card){ + // If the card has flight delete entity component + if(card in flight){ + delete flight[card]; + return true; + } + return false; +} +function giveReach(card){ + reach[card] = true; +} +function removeReach(card){ + if(card in reach){ + delete reach[card]; + return true; + } + return false; +} +function giveTaunt(card){ + taunt[card] = true; +} +function removeTaunt(card){ + // If the card has flight delete entity component + if(card in taunt){ + delete taunt[card]; + return true; + } + return false; +} + +// Active +function equip(){ + // Equip card to another unit + +} +function unequip(){ + // Remove card from its equipped to unit + +} + +function drawCard(drawAmount, player){ + board.drawACard(player, drawAmount); +} + +function heal(healAmount, healPlayer){ + // For each heal 1..4 + for(let i = 0; i < healAmount; i++){ + // Loop shield + let items = this.getItems('shield', healPlayer, null, null); + for(let item = 0; item < items.length; item++){ + + let itemKey = items[item]; + // If a shield is tapped, untap it to 'heal' + if(board.isTapped(itemKey)){ + board.untapCard(itemKey); + } + + } + } +} + +function hurt(hurtDamage, hurtTarget = null, hurtPlayer = null){ + // Deal X000 damage to unit this turn, or deal Y to opponent's shield + + // Set player/element + if(hurtPlayer == null && hurtTarget != null){ + hurtPlayer = player[hurtTarget]; + hurtElement = boardElement[hurtTarget]; + }else{ + hurtElement = 'shield' + } + + switch(hurtElement){ + case 'board': + // TODO: Make temp damage this turn as well + if(hurtDamage >= cardAttack[hurtTarget][0]){ + board.sendToGrave(hurtTarget); + } + break; + + case 'shield': + let destroyCount = cardAttackToShieldDamage(hurtDamage); + console.log(destroyCount); + // TODO: loop player's shield, tap if they can be tapped, destroy + // if all already tapped + + // While there's still damage to deal + while(destroyCount > 0){ + + // Keep looping through the shield belonging to target user + let items = board.getItems('shield', hurtPlayer, null, null); + let tappedItems = board.getItems('shield', hurtPlayer, 'tapped', null); + + for(let item = 0; item < items.length; item++){ + + // If nothing more to destroy, exit loop + if(destroyCount <= 0){ break; } + + let itemKey = items[item]; + console.log(itemKey); + console.log(cardStatus[itemKey]); + + // If there's anything to tap, tap it + if(cardStatus[itemKey] == null){ + console.log('been tapped'); + board.tapCard(itemKey); + destroyCount--; + continue; + } + + // If there's nothing to tap, destroy it + if(items.length == tappedItems.length){ + console.log('been destroyed'); + board.destroyShield(itemKey); + destroyCount--; + continue; + } + + } + } + + board.drawBoard(); + break; // end case 'shield' + + } +} + +// Effect Trigger(s) +// Non-event triggers. i.e. these are activated triggers +// rather than things such as 'On attack', 'When opponent draws' + +// When card has been actively tapped +function triggerTap(card){ + if(canTriggerTap(card) == false){ return false; } + + board.tapCard(card); + + console.log('triggerTap'); + return true; + +} +// Check a card can actively be tapped, otherwise don't start trigger +function canTriggerTap(card){ + if(board.isTapped(card)){ + return false; + } + if(boardElement[card] != 'board'){ + return false; + } + + console.log('can triggerTap'); + return true; +} + +// Pay the mana cost(s) to trigger event +function triggerPay(triggerAmount){ + if(canTriggerPay(triggerAmount) == false){ + return false; + } + + let effectCosts = [{1:0,2:0,3:0,4:0}, triggerAmount]; + board.tapManaRequired(null, 0, false, effectCosts); + + console.log('triggerPay'); + return true; + +} +// Check the mana cost(s) can be paid, otherwise don't start trigger +function canTriggerPay(triggerAmount){ + // For player0 only at the mo. and with no specific colour costs + let effectCosts = [{1:0,2:0,3:0,4:0}, triggerAmount]; + if(board.tapManaRequired(null, 0, true, effectCosts) == false){ + console.log('cannot trigger pay'); + return false; + } + + console.log('Can trigger pay'); + return true; + +} + +// Pay/Activate (all) the triggers +function doEffectTriggers(itemKey, effectIndex, checkOnly = false){ + + // Check card has effectData + let effectData = cardEffect[itemKey]; + if(effectData === undefined){ return false; } // No effect + + // Check effectData contains target effect + let effect = effectData[effectIndex]; + if(effect === undefined){ return false; } // No effect + + // Loop each trigger, AND activate them + for (const [key, value] of Object.entries(effect['trigger'])) { + + let effectTrigger = effect['trigger'][key]; + console.log('--- Trigger '+key+' ---'); + console.log(effectTrigger['triggerTypeId']); + + // TAP TRIGGER + if(effectTrigger['triggerTypeId'] == triggerTypes.tap){ + if(canTriggerTap(itemKey) == false){ + console.log('Tap trigger, cannot be triggered'); + return false; + } + + // Do the trigger, then continue to next trigger + if(!checkOnly){board.tapCard(itemKey);} + continue; + + } + + + // PAY TRIGGER + if(effectTrigger['triggerTypeId'] == triggerTypes.pay){ + + // To build the colourReq TODO: Change as could be 1 of either red/blue + // for instance + let colourReq = {1:0,2:0,3:0,4:0}; + + // Loop pay required (colours) for said trigger + // BUILD the colourReq loop needed for tapMana check + effectTrigger['target'].forEach((effectTriggerTarget) => { + + // Increment colourReq by one of that colour + // THIS WILL NEED REDOING, AS MAYBE IT'S 2 OF RED OR BLUE!! + colourReq[effectTriggerTarget.colourId]++; + + }); + + // Check if the cost (and colour req.) can be paid + canPay = board.tapManaRequired(null, null, true, [colourReq, effectTrigger['amount']]); + if(canPay !== true){ + console.log('Pay trigger, cannot be triggered'); + return false; + } + + // Pay trigger costs, then continue to next trigger + if(!checkOnly){ + board.tapManaRequired(null, null, false, [colourReq, effectTrigger['amount']]); + } + continue; + + } + + // OTHER TRIGGERS + + } + + return true; + +} + +function activateEffect(){ + // Do effect triggers, then doEffect once payed +} + +function getEffect(itemKey, effectIndex){ + // Check card has effectData + let effectData = cardEffect[itemKey]; + if(effectData === undefined){ return false; } // No effect + + // Check effectData contains target effect + let effect = effectData[effectIndex]; + if(effect === undefined){ return false; } // No effect + + return effect; +} +// Get all the targets for effect step, so they can be targgeted +// by the effect/selected by the player +function getEffectStepTargets(itemKey, effectIndex, effectStep, fromBoardElement, playerId, effectTriggerId = null){ + + // Get Effect + let effect = getEffect(itemKey, effectIndex); + if(effect == false){ return false; } + + // Get the step + let step = effect['step'][effectStep]; + if(step == undefined){ return false; } + + // The items that can be targetted with the effectStep + let itemsToSelectFrom = []; + + // Loop the target location (or all locations) + // Check which cards meet the criteria in the DB + + + // TODO: Not 100% sure how to keep track. May need a var for each item in previous steps + // or previous chains so they can be accessed, and used + // If itemFromStep, return the itemKeys of the items selected from a previous step + + console.log('HELLOO'); + console.log(step['target']); + + // TODO: If target is 'itemFromStep', then get whatever item(s) were selected in + // said step, and add them to the thing + // TODO TODO + + // If the target requirement is something from a previous step + // Check if target criteria is something from another step + let isFromStep = false; + step['target'].forEach((target) => { + if(target['itemFromStep'] != null){ + + console.log(target['itemFromStep']); + console.log(effectTriggerId); + //console.log(triggerQueue); + //console.log(triggerDone); + + // Loop all triggers that have been done (completed) + triggerDone.forEach((oldTrigger) => { + + // If not same triggerId, or the effectStep is not that of itemFromStep + if(oldTrigger['triggerId'] != effectTriggerId || target['itemFromStep'] != oldTrigger['effectStep']){ + return isFromStep = false; + } + + console.log(oldTrigger); + return isFromStep = oldTrigger['targets']; + + }); + + } + + }); + // If above returns a step, need to get the target(s) from that prior step to use a targets now + if(isFromStep){ + console.log(isFromStep); + console.log('AAAAAAAAAAAAAAAAAAAAAA'); + } + + + let items = []; + // If from a previous step, loop those + if(isFromStep !== null && isFromStep !== undefined && isFromStep !== false){ items = isFromStep; } + // If not, get all the related doodads + else{ + items = board.getItems(fromBoardElement, playerId, null, null); + } + + // Loop the boardlements and compare the colours, classes, etc. to match effect target criteria + // boardElement, playerId, cardStatus, listPosition + for(let item = 0; item < items.length; item++){ + // TODO: MAYBE ADD THE COLOUR/PASSIVE CHECKS to the getItems itself + + let itemKey = items[item]; + //console.log(cardColours[itemKey]); + + // If the item from getItems meets the criterias of target DB + step['target'].forEach((target) => { + + //console.log(target); + //console.log(triggerDone); + + + // Check the class the same for target, and item + // If targetDB has null this means 'any' so is always correct + // Check Class (TODO: mixed classes, colours, etc ie select 1 red+blue card) + /* + if(class[itemKey] == target['classId'] || target['classId'] == null){ + + } + */ + + // Check colour + // If not null check the colours, otherwise null means any colour is ok + if(target['colourId'] !== null){ + // Check the colours to see if one is of requirement + cardColours[itemKey].forEach((colour) => { + // If the colour doesn't match, continue to next target (forEach) + if(colour[0] != target['colourId']){ + // The return below is just a 'continue' in forEach terms + return; // forEach jank. forEach executes the 'function' 'target' each loop + } + // If the colour is correct, keep checking requirements + }); + } + + // Check passive (If hasPassive(id)) + /* + if(cardColours[itemKey] == target['passiveId'] || target['passiveId'] == null){ + + } + */ + + /* + if(cardType[itemKey] == target['typeId'] || target['typeId'] == null){ + + } + */ + + // Once all the target Req. have been checked against the item + // and they match, add to selectable list + itemsToSelectFrom.push(itemKey); + + }); + + } + + return itemsToSelectFrom; + + +} + +function addTargettedCardsToQueueEvent(queueTriggerId, triggerStep, targets){ + + console.log('ADD TARGETTED TO QUEUED TRIGGER'); + console.log(queueTriggerId); + console.log(triggerStep); + console.log(targets); + + //console.log(triggerQueue[queueTriggerId]); + //console.log(targets); + + console.log(triggerQueue); + + triggerQueue.forEach((queued) => { + console.log(queued); + if( + queued.triggerId == queueTriggerId + && + queued.effectStep == triggerStep + ){ + console.log('THIS SHOULD HAVE TARGETS ADDED'); + queued['targets'] = targets; + } + }); + + console.log(triggerQueue); + +} + + +function queueEffect(itemKey, effectIndex){ + + let effect = getEffect(itemKey, effectIndex); + if(effect == false){ return false; } + + // TODO: Sort steps by stepOrder incase wrong in DB, etc. + for (const [stepKey, step] of Object.entries(effect['step'])) { + triggerQueue.push( + // event, item, effectId, target, triggerId (commented atop) + { + 'event': 'effect' // Which event. attack, destroy, effect, etc. + ,'item': itemKey // Which card is doing event + ,'effectIndex': effectIndex // Which effect (if effect) + ,'effectStep': stepKey // Which effect (if effect) + ,'target': null // ? + ,'triggerId': triggerId + ,'targets': null // ? + } + ); + } + // Increment triggerId + triggerId++; + console.log(triggerQueue); +} + +function doNextInQueue(){ + + if(triggerQueue.length <= 0){ + console.log('Nothing in queue, doing next phase/event/whatever'); + } + + // If effect, trigger it (should already have paid the trigger costs) + switch(triggerQueue[0].event){ + case 'effect': + // Do the effect + doEffect(triggerQueue[0].item, triggerQueue[0].effectIndex, triggerQueue[0].effectStep, triggerQueue[0].triggerId); + break; + + default: + alert('Error in doNextInQueue'); + return 0; + break; + + + } + + // Add to completed triggers + triggerDone.push(triggerQueue[0]); + + // And remove from the triggerQueue (first index) + triggerQueue.shift(); + +} +function loopTriggerQueue(){ + + while(triggerQueue.length > 0){ + doNextInQueue(); + } + +} + +// Recusively call doEffect until each is done? +// Once recruit (play from hand) is triggered, need to allow user to select +// then when done move to next step +function doEffect(itemKey, effectIndex, effectStep, effectTriggerId){ + + console.log('doEffect'); + + let effect = getEffect(itemKey, effectIndex); + if(effect == false){ return false; } + + // Get the step + let step = effect['step'][effectStep]; + if(step == undefined){ return false; } + + + // For each step, activate the correct effect type on + // the correct targets. + + + // Get targets TODO: Use this instead of each case having it + //let targets = getEffectStepTargets(itemKey, effectIndex, effectStep, fromBoardElement, playerId, effectTriggerId); + + switch (step['basicEffectId']){ + + // Recruit + case 4: + recruitCard(itemKey, effectIndex, effectStep, step['amount'], effectTriggerId); + break; + + // Give Flight + case 5: + givePassive(itemKey, effectIndex, effectStep, step['amount'], effectTriggerId, 'flight'); + break; + + // Give Taunt + case 6: + givePassive(itemKey, effectIndex, effectStep, step['amount'], effectTriggerId, 'taunt'); + break; + + } + + // Add the selected targets to the queuedItem so it can be referred to in future + + // Now do the next step, if there's another in the effect + // Commented out while testing triggerQueue + /* + if(effect['step'][effectStep++] !== undefined){ + doEffect(itemKey, effectIndex, effectStep++); + } + */ +} + +function givePassive(itemKey, effectIndex, effectStep, targetAmount, effectTriggerId, passive){ + + console.log('GIVE PASSIVE: '+passive); + + let effect = getEffect(itemKey, effectIndex); + if(effect == false){ return false; } + + // Get the step + let step = effect['step'][effectStep]; + if(step == undefined){ return false; } + + console.log(step); + //return false; + + // TODO: null, 0 are boardElement/playerId (for now) need to redo, rethink + console.log('HELP ME'); + let targets = getEffectStepTargets(itemKey, effectIndex, effectStep, null, 0, effectTriggerId); + console.log(targets); + + if(targetAmount > 0 && targets.length > 0){ + + // TODO: better, and if just one thing omit, and do automatically + let selectedTarget = prompt("Select a card to gain flight: \n"+targets, targets[0]); + // User didn't select anything + if (selectedTarget == null || selectedTarget == "") { + alert('No card recruited, c ya'); + return false; + } + // User inputted card not in ID (obv temp, as will be done in game UI) + // Huh I forgot why this is written like this, maybe it doens't work? + if (!selectedTarget.includes(selectedTarget)){ + alert('Not in selection'); + return false; + } + + + // Remove the card from the selection (in case there's another in this loop) + targets.splice(targets.indexOf(selectedTarget), 1); + + // Give the passive + if(passive == 'flight'){ + giveFlight(selectedTarget); + } + + } + + +} + +function removePassive(){} +function hasPassive(){} + +function recruitCard(itemKey, effectIndex, effectStep, targetAmount, effectTriggerId = null){ + console.log('RECRUIT'); + + let fromBoardElement = 'hand'; // FOR NOW, JUST TO TEST, THIS WILL BE PER BASIC EFFECT + let playerId = 0; + + let targets = getEffectStepTargets(itemKey, effectIndex, effectStep, fromBoardElement, playerId, effectTriggerId); + let targettedCards = []; + + //console.log(targets); + + if(targetAmount > 0 && targets.length > 0){ + + let selectedTarget = prompt("Select a card to recruit: \n"+targets, targets[0]); + // User didn't select anything + if (selectedTarget == null || selectedTarget == "") { + alert('No card recruited, c ya'); + return false; + } + // User inputted card not in ID (obv temp, as will be done in game UI) + if (!selectedTarget.includes(selectedTarget)){ + alert('Not in selection'); + return false; + } + + // Remove the card from the selection (in case there's another) + targets.splice(targets.indexOf(selectedTarget), 1); + + // Add to targetted (for future ref) + targettedCards.push(selectedTarget); + + // Play recruited card + // TODO: Need to pass player/listPosition better? + board.playRecruitedCard(player[selectedTarget], listPosition[selectedTarget]); + + } + + addTargettedCardsToQueueEvent(effectTriggerId, effectStep, targettedCards); + +} + diff --git a/public/helper.js b/public/helper.js new file mode 100644 index 0000000..bb995ac --- /dev/null +++ b/public/helper.js @@ -0,0 +1,6 @@ +function cardAttackToShieldDamage(attack){ + if (attack >= 10000){ return 3; } + if (attack >= 5001){ return 2; } + if (attack >= 1){ return 1; } +} + diff --git a/public/index.html b/public/index.html index d0ccafc..e34efda 100644 --- a/public/index.html +++ b/public/index.html @@ -58,6 +58,63 @@ +
+
+ + + + + + + + + + + +
+ +
+
+ + + + + + + +
+ +
+
+ + + + + + +
+
@@ -69,6 +126,9 @@ + + + diff --git a/public/shapes.js b/public/shapes.js index 8313964..515d13e 100644 --- a/public/shapes.js +++ b/public/shapes.js @@ -17,6 +17,10 @@ class Shape extends Path2D{ this.fillStyle = params.fillStyle || "#FFFFFF"; this.strokeStyle = params.strokeStyle || false; this.lineWidth = params.lineWidth || 0; + this.shadow = params.shadow || false; + } + setShadow(shadow){ + this.shadow = shadow; } draw(){ //console.log('Draw Shape: '+this.name); @@ -26,6 +30,14 @@ class Shape extends Path2D{ if (this.fillStyle) { context.fillStyle = this.fillStyle; + + if(this.shadow){ + context.shadowColor = "#333"; + context.shadowOffsetX = 1; + context.shadowOffsetY = 3; + context.shadowBlur = 10; + } + if(this.shape == 'circle'){ // X,Y,Radius, start, end context.beginPath(); @@ -41,6 +53,10 @@ class Shape extends Path2D{ context.fillRect(this.x, this.y, this.width, this.height); } context.fillStyle = defaultFillStyle; // Reset back to default + context.shadowColor = 'transparent'; + context.shadowBlur = null; + context.shadowOffsetX = null; + context.shadowOffsetY = null; } if (this.strokeStyle && this.lineWidth || shapeDebug) { context.strokeStyle = this.strokeStyle;