Merge branch 'feature/basicEffects' into develop

develop
Nathan Steel 1 year ago
commit 71b3451bf7

@ -1,6 +1,7 @@
// Need to require DB again. Apparently this is ok, as it'll // Need to require DB again. Apparently this is ok, as it'll
// still only have one require cross project (?) // still only have one require cross project (?)
const database = require('./database'); const database = require('./database');
const util = require('util')
// cardClass, cardColourRequirement // cardClass, cardColourRequirement
@ -161,6 +162,118 @@ function getCardManaColour(){
}); });
return cPromise; 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(); //getCardColourRequirement();
// Then effects which will have effects with parent triggers, and unit type checks // 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) // 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 // Change SQL to accept for just the cards passed
// Get each cards data, colourReqs, and classes // Get each cards data, colourReqs, and classes
const [cards, cardClasses, cardColourRequirements, cardManaColours] = const [cards, cardClasses, cardColourRequirements, cardManaColours, cardPassives] =
await Promise.all([ await Promise.all([
getCards(), getCards(),
getCardClasses(), getCardClasses(),
getCardColourRequirement(), getCardColourRequirement(),
getCardManaColour(), getCardManaColour(),
getCardPassive(),
]); ]);
// ^^^^ Classes async? Can pass the cardsIds, then loop classes, if the class cardId // ^^^^ 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 // 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.info(cardClasses);
//console.log(cardColourRequirements); //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] = const [builtCards] =
await Promise.all([ await Promise.all([
buildCards(cards, cardClasses, cardColourRequirements, cardManaColours), buildCards(cards, cardClasses, cardColourRequirements, cardManaColours, cardEffects, cardPassives),
// TODO: builtEffects
]); ]);
//console.log(builtCards); //console.log(builtCards);
@ -285,6 +417,10 @@ function requestDeck(itemData = null){
let cardAttack = {}; // Base, Current let cardAttack = {}; // Base, Current
let cardSprite = {}; // Maybe from DB? let cardSprite = {}; // Maybe from DB?
let cardManaColour = {}; // The card colour value when played in mana zone 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 // TODO: Set the player. For now will do this in front-end as testing currently
@ -349,6 +485,35 @@ function requestDeck(itemData = null){
cardAttack[itemCount] = [atk, atk]; // Base, Current cardAttack[itemCount] = [atk, atk]; // Base, Current
player[itemCount] = forPlayer; // Jank TODO: actually set to correct player 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 itemCount++; // Increment item to not overwrite
} }
@ -371,6 +536,9 @@ function requestDeck(itemData = null){
itemData.cardAttack = cardAttack; itemData.cardAttack = cardAttack;
itemData.cardSprite = cardSprite; itemData.cardSprite = cardSprite;
itemData.cardManaColour = cardManaColour; itemData.cardManaColour = cardManaColour;
itemData.cardEffect = cardEffect;
itemData.flight = flight;
itemData.reach = reach;
// item, itemCount, deckData, cardData, boardElement // item, itemCount, deckData, cardData, boardElement
//console.log(cardData); //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 // 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); console.log(cardColourRequirements);
const dPromise = new Promise((resolve, reject) => { const dPromise = new Promise((resolve, reject) => {
@ -419,6 +587,7 @@ function buildCards(cards, cardClasses, cardColourRequirements, cardManaColours)
rarity: card.cardRarity, rarity: card.cardRarity,
effect: [], effect: [],
cardClass: [], cardClass: [],
passive: [],
}; };
// Give the card an easily accessible Id for compares // Give the card an easily accessible Id for compares
// and to add to the cardItem being built // 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); resolve(builtCards);
}); });

@ -124,6 +124,104 @@ function dbGetCardManaColour(){
return cPromise; 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 = { module.exports = {
connect, disconnect connect, disconnect
// Testing, and trailing // Testing, and trailing
@ -133,4 +231,8 @@ module.exports = {
, dbGetCardClasses , dbGetCardClasses
, dbGetCardColourRequirement , dbGetCardColourRequirement
, dbGetCardManaColour , dbGetCardManaColour
, dbGetEffect
, dbGetEffectStep
, dbGetEffectTrigger
, dbGetPassive
}; };

@ -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');

@ -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);

@ -0,0 +1,2 @@
INSERT INTO `passive` (`id`, `passiveName`, `passiveDescription`) VALUES (3, 'Taunt', 'Must be targetted by attacks');

@ -40,6 +40,7 @@ let deckData = {};
let cardAttack = {}; // TODO: add to the logic let cardAttack = {}; // TODO: add to the logic
let cardColours = {}; let cardColours = {};
let cardManaColour = {}; let cardManaColour = {};
let cardEffect = {};
let inEvent = null; let inEvent = null;
// To disable drawing each time something changes // To disable drawing each time something changes
@ -215,6 +216,10 @@ class Board{
fillStyle: fill, fillStyle: fill,
strokeStyle: border strokeStyle: border
}); });
// Add a dropshadow to flight cards (they're flyin)
if(flight[itemKey]){
shape.setShadow(true);
}
shape.draw(); shape.draw();
// Draw the card face-up // Draw the card face-up
@ -222,6 +227,7 @@ class Board{
this.addCardImage(itemKey); this.addCardImage(itemKey);
this.printCardDetails(itemKey); this.printCardDetails(itemKey);
this.printColourRequirements(itemKey); this.printColourRequirements(itemKey);
this.printCardPassives(itemKey);
} }
if(!this.isFaceUp(itemKey)){ if(!this.isFaceUp(itemKey)){
this.addCardBack(itemKey); this.addCardBack(itemKey);
@ -346,6 +352,27 @@ class Board{
// TODO: CardBack/Sleeves as spritesheet like cardArt // TODO: CardBack/Sleeves as spritesheet like cardArt
ctx.drawImage(cardBackArt, 0,0, 80,120,positionX,positionY,width,height); 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){ printColourRequirements(itemKey){
// Set the size(s) // Set the size(s)
let width = size[itemKey][0]*.1; 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 // Currently only functionality in hand
playCardToBoard(positionFrom, fromElement, toElement, fromPlayer, toPlayer = null, cardsToPlay = 1){ 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.summonCard(fromPlayer, positionFrom, fromElement, toPlayer);
this.addFromBoardElement(fromPlayer, positionFrom, fromElement, toElement, null, toPlayer);
} }
this.drawBoard(); 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() // 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 noManaReq = {1:0, 2:0, 3:0, 4:0};
let manaToTap = []; let manaToTap = [];
@ -700,7 +759,6 @@ class Board{
console.log(JSON.stringify(manaRequired[0])); console.log(JSON.stringify(manaRequired[0]));
// Loop the requirements of the cost to pay // Loop the requirements of the cost to pay
for (const manaColour in manaRequired[0]) { for (const manaColour in manaRequired[0]) {
//console.log(manaColour+' '+manaRequired[manaColour]+', '+colourId);
// If the colour of the mana is in the requirements // If the colour of the mana is in the requirements
// of the cost to pay, reduce the cost for that colour by // of the cost to pay, reduce the cost for that colour by
// 1 and tap the mana // 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) // For 3 cost cards that only require 1 red, two more mana (any colour)
// need to be tapped // need to be tapped
// TODO: Better more efficiently and let user select... // TODO: Better more efficiently and let user select...
let itemCostRemaining = cardData[itemToPayCost].cost - manaRequired[1]; let itemCostRemaining = 0;
if(itemCostRemaining > 0){ let itemCost = 0;
/* if(itemToPayCost !== null){
let tapRequirement = (cardData[itemToPayCost].cost - manaRequired[1]); itemCostRemaining = cardData[itemToPayCost].cost - manaRequired[1];
alert('Tap: '+(tapRequirement)+' more mana to play'); 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 // 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. // 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 // For now, reloop and tap first available mana so that card
// payment is satiated // payment is satiated
// Using same items from above // Using same items from above
@ -749,18 +815,21 @@ class Board{
} }
manaToTap.push(mana); 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 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 // If the mana to tap has been satitated then tap the mana selected
manaToTap.forEach(manaId => { if(checkOnly == false){ // Tap the mana if this isn't a check
this.tapCard(manaId); manaToTap.forEach(manaId => {
}); this.tapCard(manaId);
});
}
// And continue with whatever we were doing // And continue with whatever we were doing
return true; return true;
@ -976,6 +1045,12 @@ class Board{
let atkAttacker = this.attackOf(itemAttacking); let atkAttacker = this.attackOf(itemAttacking);
let atkDefender = this.attackOf(itemDefending); 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 // Does Attacker kill Defender
if(atkDefender <= atkAttacker){ if(atkDefender <= atkAttacker){
this.sendToGrave(itemDefending); this.sendToGrave(itemDefending);
@ -993,6 +1068,13 @@ class Board{
break; break;
case 'shield': 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 the shield is tapped 'destroy' it
if(this.isTapped(itemDefending)){ if(this.isTapped(itemDefending)){
if(!this.destroyShield(itemDefending)){ if(!this.destroyShield(itemDefending)){
@ -1012,6 +1094,58 @@ class Board{
this.drawBoard(); 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){ attackOf(itemKey){
// TODO: Change this to ECSey element when added // TODO: Change this to ECSey element when added
return cardData[itemKey]; return cardData[itemKey];
@ -1169,6 +1303,11 @@ function loadBoard(data) {
cardAttack = data.cardAttack; // TODO: add to the logic cardAttack = data.cardAttack; // TODO: add to the logic
cardColours = data.cardColours; cardColours = data.cardColours;
cardManaColour = data.cardManaColour; cardManaColour = data.cardManaColour;
cardEffect = data.cardEffect;
// Passives
flight = data.flight;
reach = data.reach;
// TODO: JANK IN, CHANGE CODE TO USE NEW ARRAY!! // TODO: JANK IN, CHANGE CODE TO USE NEW ARRAY!!
// Temp jank, set colour to first colour req. // Temp jank, set colour to first colour req.
@ -1243,6 +1382,10 @@ canvas.addEventListener('contextmenu', function(event) {
if(itemKey in size && itemKey in position){ if(itemKey in size && itemKey in position){
// Compare the event XY position to the item // Compare the event XY position to the item
if(clickableCheck(x,y,itemKey)){ 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) // Only want to happen once (for now)
// Maybe in future add to hand would trigger another event if there's an effect? // 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'){ if(itemPlayer == 0 && itemElement == 'board'){
positionX = canvas.width/2 - (cardWidth * (itemListLength - (i+1)) - (cardMargin * (i+1))); positionX = canvas.width/2 - (cardWidth * (itemListLength - (i+1)) - (cardMargin * (i+1)));
positionY = canvas.height - cardHeight-30-(cardHeight); positionY = canvas.height - cardHeight-30-(cardHeight);
// Move up to denote 'Flight' keyword
if(flight[itemKey]){
positionY-=10;
}
width = cardWidth; width = cardWidth;
height = cardHeight; height = cardHeight;
} }
@ -1644,7 +1791,8 @@ function printECSData(items){
'deckData: '+deckData[itemKey]+"\n"+ 'deckData: '+deckData[itemKey]+"\n"+
'cardAttack: '+cardAttack[itemKey]+"\n"+ 'cardAttack: '+cardAttack[itemKey]+"\n"+
'cardColours: '+cardColours[itemKey]+"\n"+ 'cardColours: '+cardColours[itemKey]+"\n"+
'cardManaColour: '+cardManaColour[itemKey] 'cardManaColour: '+cardManaColour[itemKey]+"\n"+
'cardEffect: '+cardEffect[itemKey]
); );
} }
} }

@ -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();
}

@ -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);
}

@ -0,0 +1,6 @@
function cardAttackToShieldDamage(attack){
if (attack >= 10000){ return 3; }
if (attack >= 5001){ return 2; }
if (attack >= 1){ return 1; }
}

@ -58,6 +58,63 @@
</select> </select>
</div> </div>
<hr>
<div>
<button onclick="debugEffect();">Debug Effect</button>
<input type="text" placeholder="damage amount (X000s)" id="effectDamageAmount">
<input type="text" placeholder="targetId" id="effectTargetId">
<input type="text" placeholder="targetId2" id="effectTargetId2">
<input type="text" placeholder="targetPlayer" id="effectTargetPlayer">
<select name="effectAddRemove" id="effectAddRemove">
<option value="add">Add</option>
<option value="remove">Remove</option>
</select>
<select name="effect" id="effect">
<option value="hurt">Hurt</option>
<option value="heal">Heal</option>
<option value="draw">Draw</option>
<option value="">-- Add/Remove --</option>
<option value="flight">Flight</option>
<option value="reach">Reach</option>
<option value="taunt">Taunt</option>
<option value="equipCard">Equip</option>
<option value="unequipCard">unEquip</option>
</select>
</div>
<hr>
<div>
<button onclick="debugTrigger();">Debug Trigger</button>
<input type="text" placeholder="targetId" id="triggerTargetId">
<select id="trigger">
<option value="tap">Tap</option>
<option value="pay">Pay</option>
</select>
<input placeholder="Amount" id="triggerAmount">
</div>
<hr>
<div>
<button onclick="debugEffectCanTrigger();">Debug Effect Can Trigger</button>
<input type="text" placeholder="targetId" id="ecTriggerTargetId">
<input type="text" placeholder="effectIndex" id="ecTriggerIndex">
<select id="ecDoTrigger">
<option value="0">Just Check</option>
<option value="1">Trigger Effect</option>
</select>
</div>
<hr> <hr>
<div> <div>
<button onclick="requestStartGame()">(Re)start game</button> <button onclick="requestStartGame()">(Re)start game</button>
@ -69,6 +126,9 @@
<script src="/shapes.js"></script> <script src="/shapes.js"></script>
<script src="/main.js"></script> <script src="/main.js"></script>
<script src="/board.js"></script> <script src="/board.js"></script>
<script src="/helper.js"></script>
<script src="/effect.js"></script>
<script src="/debug.js"></script>
</body> </body>
</html> </html>

@ -17,6 +17,10 @@ class Shape extends Path2D{
this.fillStyle = params.fillStyle || "#FFFFFF"; this.fillStyle = params.fillStyle || "#FFFFFF";
this.strokeStyle = params.strokeStyle || false; this.strokeStyle = params.strokeStyle || false;
this.lineWidth = params.lineWidth || 0; this.lineWidth = params.lineWidth || 0;
this.shadow = params.shadow || false;
}
setShadow(shadow){
this.shadow = shadow;
} }
draw(){ draw(){
//console.log('Draw Shape: '+this.name); //console.log('Draw Shape: '+this.name);
@ -26,6 +30,14 @@ class Shape extends Path2D{
if (this.fillStyle) { if (this.fillStyle) {
context.fillStyle = 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'){ if(this.shape == 'circle'){
// X,Y,Radius, start, end // X,Y,Radius, start, end
context.beginPath(); context.beginPath();
@ -41,6 +53,10 @@ class Shape extends Path2D{
context.fillRect(this.x, this.y, this.width, this.height); context.fillRect(this.x, this.y, this.width, this.height);
} }
context.fillStyle = defaultFillStyle; // Reset back to default 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) { if (this.strokeStyle && this.lineWidth || shapeDebug) {
context.strokeStyle = this.strokeStyle; context.strokeStyle = this.strokeStyle;

Loading…
Cancel
Save