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