|
|
|
|
@ -28,24 +28,14 @@ let player = {};
|
|
|
|
|
let listPosition = {};
|
|
|
|
|
let inEvent = null;
|
|
|
|
|
|
|
|
|
|
// TODO: Do something else ECSey, think most logic for this is about
|
|
|
|
|
let playerDeck = [];
|
|
|
|
|
let opponentDeck = [];
|
|
|
|
|
// TODO: Re-implement, then remove existing code
|
|
|
|
|
let playerMana = [];
|
|
|
|
|
let playerHand = [];
|
|
|
|
|
|
|
|
|
|
// To disable drawing each time something changes
|
|
|
|
|
let drawEachEvent = true; // For disabling draw each time and only occuring where I want to test
|
|
|
|
|
let yourPlayerId = 0; // To compare click events of your/opponents cards
|
|
|
|
|
let viewingPlayerId = 0; // To show the board from your/opponent/teammates perspective, etc. without play permission
|
|
|
|
|
|
|
|
|
|
let deckCount = 35;
|
|
|
|
|
let deckCountOpponent = 35;
|
|
|
|
|
|
|
|
|
|
const maxHandSize = 4;
|
|
|
|
|
const maxBoardSize = 3;
|
|
|
|
|
const maxShield = 4;
|
|
|
|
|
const maxShield = 2;
|
|
|
|
|
|
|
|
|
|
// Gonna need lots of refactoring, and sorting
|
|
|
|
|
class Board{
|
|
|
|
|
@ -69,7 +59,7 @@ class Board{
|
|
|
|
|
|
|
|
|
|
this.drawPlayerNames('Nathan', 'Evil Nathan');
|
|
|
|
|
|
|
|
|
|
this.drawCardsECS(); // Atop most everything atm for testing
|
|
|
|
|
this.drawItems(); // Atop most everything atm for testing
|
|
|
|
|
|
|
|
|
|
if(this.checkGameWin() == true){
|
|
|
|
|
this.drawWin();
|
|
|
|
|
@ -110,31 +100,24 @@ class Board{
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
drawCardsECS(){
|
|
|
|
|
// ALL NON DECK CARDS DO BE DRAWN IN SAME LOOP (ideally)
|
|
|
|
|
drawItems(){
|
|
|
|
|
// Loop all items
|
|
|
|
|
for(let itemKey = 0; itemKey < item.length; itemKey++){
|
|
|
|
|
|
|
|
|
|
// Loop each element, and player
|
|
|
|
|
// Loop each element to draw (each have distinct locations, and draw logic)
|
|
|
|
|
for(let elementCount in elements){
|
|
|
|
|
|
|
|
|
|
// Don't draw deck TODO:/gy/void
|
|
|
|
|
// TODO: Unless inspecting
|
|
|
|
|
let element = elements[elementCount];
|
|
|
|
|
if(element == 'deck'){
|
|
|
|
|
if(element == 'deck' || element == 'grave'){
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw Elements
|
|
|
|
|
// Loop each item left, and draw if element is currently looped. board,mana,etc.
|
|
|
|
|
// Loop each item remaining, draw them
|
|
|
|
|
if(itemKey in boardElement && boardElement[itemKey] == element){
|
|
|
|
|
if(boardElement[itemKey] == 'board' && player[itemKey] == 0){
|
|
|
|
|
console.log('PLAYER BOARD');
|
|
|
|
|
}
|
|
|
|
|
// Get the player the item belongs to
|
|
|
|
|
let itemPlayer = player[itemKey];
|
|
|
|
|
//console.log('Element: '+element+', Player: '+itemPlayer);
|
|
|
|
|
|
|
|
|
|
calculateItemSizePosition(itemKey);
|
|
|
|
|
|
|
|
|
|
this.printCardToCanvas(itemKey);
|
|
|
|
|
@ -149,8 +132,8 @@ class Board{
|
|
|
|
|
|
|
|
|
|
// Check status, and change border colour for display (for tapped atm)
|
|
|
|
|
let border = null;
|
|
|
|
|
if(cardStatus[itemKey] == 'tapped'){border = '#E0BC00';}
|
|
|
|
|
if(cardStatus[itemKey] == 'attacking'){border = '#C92D22';}
|
|
|
|
|
if(this.isTapped(itemKey)){border = '#E0BC00';}
|
|
|
|
|
if(this.isAttacking(itemKey)){border = '#C92D22';}
|
|
|
|
|
|
|
|
|
|
// Set the card 'cardboard' colour based on the card colour type
|
|
|
|
|
let fill = null;
|
|
|
|
|
@ -287,268 +270,162 @@ class Board{
|
|
|
|
|
ctx.font = "10pt Arial";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw Invidual Cards, called by other deck stuff
|
|
|
|
|
// Might be put into a card class, makes sense, eh.
|
|
|
|
|
drawCard(array, arrayKey, name, positionX, positionY, width, height, fill, border){
|
|
|
|
|
// Card Colour
|
|
|
|
|
//console.log('drawCard card: '+JSON.stringify(array[arrayKey]));
|
|
|
|
|
let colourId = array[arrayKey].colour;
|
|
|
|
|
if(colourId == 0){ fill = '#EEE' }
|
|
|
|
|
else if(colourId == 1){ fill = '#0033EE' }
|
|
|
|
|
|
|
|
|
|
if(array[arrayKey].tapped){
|
|
|
|
|
border = '#E0BC00';
|
|
|
|
|
console.log('drawCard tapped');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var cardClickable = new Shape({
|
|
|
|
|
name: name,
|
|
|
|
|
x: positionX,
|
|
|
|
|
y: positionY,
|
|
|
|
|
width: width,
|
|
|
|
|
height: height,
|
|
|
|
|
fillStyle: fill,
|
|
|
|
|
strokeStyle: border
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
array[arrayKey]['clickable'] = cardClickable;
|
|
|
|
|
array[arrayKey]['clickable'].draw();
|
|
|
|
|
|
|
|
|
|
// Add image
|
|
|
|
|
// TODO:half circle for unit Set start angle to 0 and end angle to Math.PI.
|
|
|
|
|
// TODO:Ellipse for token (near full size)
|
|
|
|
|
// TODO:Octagon for spell
|
|
|
|
|
let cardImageContainer = new Shape({
|
|
|
|
|
shape: 'semi',
|
|
|
|
|
name: 'cardImageContainer_'+name,
|
|
|
|
|
x: positionX+height/3,
|
|
|
|
|
y: positionY+width/2,
|
|
|
|
|
width: width*.9,
|
|
|
|
|
height: height*.9,
|
|
|
|
|
fillStyle: "#BBB"
|
|
|
|
|
});
|
|
|
|
|
cardImageContainer.draw();
|
|
|
|
|
|
|
|
|
|
// Add card name
|
|
|
|
|
let fontSize = width/cardWidth*10; // 10 = baseFontSize of 10pt
|
|
|
|
|
ctx.font = "bold "+fontSize+"pt Arial";
|
|
|
|
|
ctx.fillStyle = '#000';
|
|
|
|
|
ctx.fillText(
|
|
|
|
|
array[arrayKey]['name']
|
|
|
|
|
, positionX + (ctx.measureText(array[arrayKey]['name']/2).width) - width/4
|
|
|
|
|
, positionY+height*.25
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Add card type
|
|
|
|
|
ctx.fillText(
|
|
|
|
|
array[arrayKey]['type']
|
|
|
|
|
, positionX + (ctx.measureText(array[arrayKey]['type']/2).width) - width/4
|
|
|
|
|
, positionY+height*.7
|
|
|
|
|
);
|
|
|
|
|
// Add text/effect area
|
|
|
|
|
if(array[arrayKey]['effect'] !== null){
|
|
|
|
|
ctx.fillText(
|
|
|
|
|
array[arrayKey]['effect']
|
|
|
|
|
, positionX + (ctx.measureText(array[arrayKey]['effect']/2).width) - width/4
|
|
|
|
|
, positionY+height*.8
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
// Attack
|
|
|
|
|
ctx.fillText(
|
|
|
|
|
array[arrayKey]['atk']
|
|
|
|
|
, positionX + (ctx.measureText(array[arrayKey]['atk']).width)
|
|
|
|
|
, positionY+height*.95
|
|
|
|
|
);
|
|
|
|
|
// Add cost
|
|
|
|
|
ctx.fillText(
|
|
|
|
|
array[arrayKey]['cost']
|
|
|
|
|
, positionX + (ctx.measureText(array[arrayKey]['cost']).width)
|
|
|
|
|
, positionY+height*.1
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Unbold font for other draws
|
|
|
|
|
ctx.font = "10pt Arial";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// boardElement, cardData?, position?, size?, cardStatus, player, listPosition
|
|
|
|
|
getItems(boardElementId = null, playerId = null, cardStatusId = null, listPositionId = null){
|
|
|
|
|
// So, the intent here is to normalise my nested loop I keep duping (parts of)
|
|
|
|
|
// This will recieve each piece of content that can be stored in each ECS element
|
|
|
|
|
// Then will loop each individually, setting a new array to be returned
|
|
|
|
|
// This new array will then be used for tapping, untapping, moving positions, etc.
|
|
|
|
|
|
|
|
|
|
// This is the 'core' of the loop, as it'll keep changing what's in it, removing
|
|
|
|
|
// elements at each step. I.e. Will check boardElement for 'mana', removing all other boardElements
|
|
|
|
|
// Then with just the 'mana' elements will check the player. OR can return all mana, OR all player items
|
|
|
|
|
// Loop each item, building a new (smaller) loop each time an ECSey element
|
|
|
|
|
// matches what was passed. This is the core loop for practically every function.
|
|
|
|
|
let newItems = [];
|
|
|
|
|
let tempArray = [];
|
|
|
|
|
|
|
|
|
|
// Set to all items in itemArray to start
|
|
|
|
|
newItems = item;
|
|
|
|
|
|
|
|
|
|
//let elements = ['deck','board','hand','mana','shield', 'grave'];
|
|
|
|
|
// Stuff to be looped, and compared
|
|
|
|
|
//let boardElement = {};
|
|
|
|
|
//let cardData = {};
|
|
|
|
|
//let position = {};
|
|
|
|
|
//let size = {};
|
|
|
|
|
//let cardStatus = {}; // tapped, attacking, inspected, untargettable (TODO:maybe used this instead of inEvent later)
|
|
|
|
|
//let player = {};
|
|
|
|
|
//let listPosition = {};
|
|
|
|
|
|
|
|
|
|
// These have been re-ordered to try to minise looping
|
|
|
|
|
// Example, player in theory halfs the cards instantly, whereas boardElement deck, may do little
|
|
|
|
|
// boardElement often will be better though, but???
|
|
|
|
|
|
|
|
|
|
// PLAYER
|
|
|
|
|
// Check if each item shares the PLAYERID passed
|
|
|
|
|
if(playerId !== null){
|
|
|
|
|
for(let newItem = 0; newItem < newItems.length; newItem++){
|
|
|
|
|
// newItems[newItem] gets the original itemKey (needed), newItem would be
|
|
|
|
|
// the the array index, which would be wrong in most cases in this function.
|
|
|
|
|
let itemKey = newItems[newItem];
|
|
|
|
|
// If the playerId of item shares the passed playerId
|
|
|
|
|
// If the item shares the playerId, add it to the tempArray
|
|
|
|
|
if(playerId == player[itemKey]){
|
|
|
|
|
tempArray.push(newItems[newItem]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Set newItems to what remains in tempArray
|
|
|
|
|
// Set newItems to tempArray so it can be looped again with only what matched
|
|
|
|
|
newItems = tempArray;
|
|
|
|
|
}
|
|
|
|
|
// Reset tempArray so it can be reused
|
|
|
|
|
tempArray = [];
|
|
|
|
|
|
|
|
|
|
// CARD STATUS
|
|
|
|
|
// Next check if each remaining item shares the CARDSTATUS passed
|
|
|
|
|
if(cardStatusId !== null){
|
|
|
|
|
for(let newItem = 0; newItem < newItems.length; newItem++){
|
|
|
|
|
let itemKey = newItems[newItem];
|
|
|
|
|
// If the playerId of item shares the passed playerId
|
|
|
|
|
// If the item shares the cardStatusId, add it to the tempArray
|
|
|
|
|
if(cardStatusId == cardStatus[itemKey]){
|
|
|
|
|
tempArray.push(newItems[newItem]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Set newItems to what remains in tempArray
|
|
|
|
|
// Set newItems to tempArray so it can be looped again with only what matched
|
|
|
|
|
newItems = tempArray;
|
|
|
|
|
}
|
|
|
|
|
// Reset tempArray so it can be reused
|
|
|
|
|
tempArray = [];
|
|
|
|
|
|
|
|
|
|
// LIST POSITION
|
|
|
|
|
// Next check if each remaining item shares the LISTPOSITION passed
|
|
|
|
|
if(listPositionId !== null){
|
|
|
|
|
for(let newItem = 0; newItem < newItems.length; newItem++){
|
|
|
|
|
let itemKey = newItems[newItem];
|
|
|
|
|
// If the playerId of item shares the passed playerId
|
|
|
|
|
// If the item shares the cardStatusId, add it to the tempArray
|
|
|
|
|
if(listPositionId == listPosition[itemKey]){
|
|
|
|
|
tempArray.push(newItems[newItem]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Set newItems to what remains in tempArray
|
|
|
|
|
// Set newItems to tempArray so it can be looped again with only what matched
|
|
|
|
|
newItems = tempArray;
|
|
|
|
|
}
|
|
|
|
|
// Reset tempArray so it can be reused
|
|
|
|
|
tempArray = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// BOARD ELEMENT
|
|
|
|
|
// Loop items for boardElement of elementType passed
|
|
|
|
|
// Only do the loop if the element type was passed too, no reason to waste resources
|
|
|
|
|
// Next check if each remaining item shares the BOARDELEMENT passed
|
|
|
|
|
if(boardElementId !== null){
|
|
|
|
|
for(let newItem = 0; newItem < newItems.length; newItem++){
|
|
|
|
|
// Add the itemKey to tempArray
|
|
|
|
|
// itemKey can be different to the array's elementId, and we want the original itemKey,
|
|
|
|
|
// not the new elementId, as that would then add the wrong item
|
|
|
|
|
|
|
|
|
|
// Set the itemKey, so things make sense
|
|
|
|
|
let itemKey = newItems[newItem]; //newItems[0] could be itemKey 12, so want the content
|
|
|
|
|
|
|
|
|
|
// If the boardElement of item shares the passed boardElement add it to current return
|
|
|
|
|
let itemKey = newItems[newItem];
|
|
|
|
|
// If the item shares the boardElement, add it to the tempArray
|
|
|
|
|
if(boardElementId == boardElement[itemKey]){
|
|
|
|
|
tempArray.push(newItems[newItem]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set newItems to what remains in tempArray
|
|
|
|
|
// Set newItems to tempArray so it can be looped again with only what matched
|
|
|
|
|
newItems = tempArray;
|
|
|
|
|
}
|
|
|
|
|
// Reset tempArray so it can be reused
|
|
|
|
|
tempArray = [];
|
|
|
|
|
|
|
|
|
|
// Return the new specified itemList
|
|
|
|
|
return newItems;
|
|
|
|
|
|
|
|
|
|
// TODO: May look at restructuring this again. Maybe one loop with each check against
|
|
|
|
|
// the element data passed. Depends on which seems fastest, may do a compare on a large
|
|
|
|
|
// dataset to see
|
|
|
|
|
// TODO: ALSO in different func, Something like x.element.player.status to return the itemKey?
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//TODO: Change vars to newPosition, newElement, newPlayer, oldPosition, oldElement, oldPlayer
|
|
|
|
|
addFromBoardElement(playerFrom, fromPosition, elementFrom, elementTo, toPosition=null, playerTo=null){
|
|
|
|
|
// Move itemKey fromPosition in elementFrom to toPosition in elementTo
|
|
|
|
|
// can also switch item between players (of from and to supplied)
|
|
|
|
|
// Move itemKey fromPosition in elementFrom from playerFrom
|
|
|
|
|
// to toPosition in elementTo for playerTo
|
|
|
|
|
|
|
|
|
|
// If no playerTo provided (typical behavior), pass between elements for same player
|
|
|
|
|
if(playerTo == null){
|
|
|
|
|
playerTo = playerFrom;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if there's more than 1 thing add that position (something's gone wrong somewhere)
|
|
|
|
|
// Check there is only 1 item that exists with the from info
|
|
|
|
|
let items = this.getItems(elementFrom, playerFrom, null, fromPosition);
|
|
|
|
|
if(board.getItems(elementFrom, playerFrom, null, fromPosition).length > 1){
|
|
|
|
|
alert('ERROR: There are more than 1 card being added');
|
|
|
|
|
if(items.length > 1){
|
|
|
|
|
alert('ERROR: There is more than 1 card being added');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// First (and only) item returned is the key thins should be done with
|
|
|
|
|
// The first (and only) item returned
|
|
|
|
|
let itemKey = items[0];
|
|
|
|
|
|
|
|
|
|
if(listPosition[itemKey] == fromPosition){
|
|
|
|
|
// Check if a toPostion supplied
|
|
|
|
|
// Check if there is a specific position the item needs to go to
|
|
|
|
|
if(toPosition == null){
|
|
|
|
|
// Get the new position of item based on new boardElement
|
|
|
|
|
// If not get the next available position of the elementTo
|
|
|
|
|
toPosition = getCurrentPositionAndLength(elementTo, playerTo)[0]+1
|
|
|
|
|
}
|
|
|
|
|
//console.log('itemKey: '+itemKey+' fromPosition: '+fromPosition+' elementFrom: '+elementFrom+' elementTo: '+elementTo+' toPosition: '+toPosition+' playerFrom: '+playerFrom+' playerTo: '+playerTo);
|
|
|
|
|
|
|
|
|
|
// Move item to it's new position
|
|
|
|
|
listPosition[itemKey] = toPosition;
|
|
|
|
|
// Move item to it's new element
|
|
|
|
|
boardElement[itemKey] = elementTo;
|
|
|
|
|
|
|
|
|
|
// Move down(0) the positions of elementFrom, from fromPosition for player
|
|
|
|
|
this.moveElementPositions(0, elementFrom, fromPosition, playerFrom);
|
|
|
|
|
// TODO: rename function this lives in to vars accepted by setCardPosition function, more sense
|
|
|
|
|
this.setCardPosition(itemKey, toPosition, elementTo, playerTo, fromPosition, elementFrom, playerFrom);
|
|
|
|
|
|
|
|
|
|
this.removeItemStatus(itemKey);
|
|
|
|
|
this.drawBoard();
|
|
|
|
|
return 1; // Got a loop that calls a loop, and checks the new values atm, so this keeps counting down
|
|
|
|
|
}
|
|
|
|
|
// This took me a while to think through. It makes sense, don't change.
|
|
|
|
|
// Get a pen and paper and just work through an array of 0..5 moving some number about
|
|
|
|
|
setCardPosition(card, newPosition, newElement, newPlayer, oldPosition, oldElement, oldPlayer){
|
|
|
|
|
// Move anything in the old boardElement after the old listPosition down by one
|
|
|
|
|
// Coming from position 3, moves existing 4..10 down one to 3..9
|
|
|
|
|
// Moving from pos 5 = 6,7,8 go down to 5,6,7
|
|
|
|
|
this.moveElementPositions(0, oldElement, oldPosition, oldPlayer);
|
|
|
|
|
|
|
|
|
|
// Move anything in the new boardElement after (including) the new listPosition up by one
|
|
|
|
|
// Going to position 3, moves existing 3..10 up one to 4..11 to make space
|
|
|
|
|
// Moving back to pos 5 = current 5,6,7 go up to 6,7,8
|
|
|
|
|
this.moveElementPositions(1, newElement, newPosition, newPlayer);
|
|
|
|
|
|
|
|
|
|
// Then fit the card into the new gap that's opened up
|
|
|
|
|
listPosition[card] = newPosition;
|
|
|
|
|
boardElement[card] = newElement;
|
|
|
|
|
}
|
|
|
|
|
moveElementPositions(direction, elementFrom, fromPosition, playerFrom){
|
|
|
|
|
|
|
|
|
|
// Move the positions directionally 1 for elementFrom from fromPosition
|
|
|
|
|
//console.log(listPosition);
|
|
|
|
|
//console.log('Direction: '+direction+' elementFrom: '+elementFrom+' fromPosition: '+fromPosition+' player: '+playerId);
|
|
|
|
|
|
|
|
|
|
// Loop the elementFrom, and move positions for anything after
|
|
|
|
|
// item taken from position 34, 35..60 need to be moved down to 34..59
|
|
|
|
|
// Loop the elementFrom, and move positions up/down by one
|
|
|
|
|
let items = this.getItems(elementFrom, playerFrom, null, null);
|
|
|
|
|
for(let item = 0; item < items.length; item++){
|
|
|
|
|
let itemKey = items[item];
|
|
|
|
|
if(listPosition[itemKey] > fromPosition){
|
|
|
|
|
// Move items up, i.e. added to top of deck
|
|
|
|
|
if(direction){
|
|
|
|
|
listPosition[itemKey]++;
|
|
|
|
|
}
|
|
|
|
|
// Move items down, i.e. taken from top of deck
|
|
|
|
|
// Move everything after the old position down
|
|
|
|
|
// Moving from pos 5 = 6,7,8 go down to 5,6,7
|
|
|
|
|
if(direction == 0 && listPosition[itemKey] > fromPosition){
|
|
|
|
|
listPosition[itemKey]--;
|
|
|
|
|
}
|
|
|
|
|
// Move everything from the new position up
|
|
|
|
|
// Moving back to pos 5 = current 5,6,7 go up to 6,7,8
|
|
|
|
|
if(direction == 1 && listPosition[itemKey] >= fromPosition){
|
|
|
|
|
listPosition[itemKey]++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Draw a card, traditional TCG
|
|
|
|
|
drawACard(playerId, cardsToDraw = 1){
|
|
|
|
|
for(let draw = 0; draw < cardsToDraw; draw++){
|
|
|
|
|
// Move from player1, position 0 (top) of deck, to hand
|
|
|
|
|
|
|
|
|
|
// Check there's space in hand
|
|
|
|
|
let elementLength = getCurrentPositionAndLength('hand', playerId)[1];
|
|
|
|
|
if(elementLength >= maxHandSize){
|
|
|
|
|
alert('Hand full '+elementLength+'/'+maxHandSize);
|
|
|
|
|
return 0;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Move from players deck to hand, from position 1 (bottom deck)
|
|
|
|
|
this.addFromBoardElement(playerId, 1, 'deck', 'hand', null, null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -622,6 +499,7 @@ class Board{
|
|
|
|
|
return itemKey[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: Make this work for each element
|
|
|
|
|
hasSpaceInBoardElement(toElement, toPlayer){
|
|
|
|
|
|
|
|
|
|
let elementLength = getCurrentPositionAndLength(toElement, toPlayer)[1];
|
|
|
|
|
@ -662,30 +540,48 @@ class Board{
|
|
|
|
|
inEvent = ['inspect', cardToInspect];
|
|
|
|
|
this.drawBoard();
|
|
|
|
|
}
|
|
|
|
|
isInEvent(eventToCheck = null){
|
|
|
|
|
if(eventToCheck == null && inEvent){
|
|
|
|
|
// If in any event
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if(inEvent && inEvent[0] == eventToCheck){
|
|
|
|
|
// If in specified event
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
cancelInspect(){
|
|
|
|
|
if(inEvent && inEvent[0] == 'inspect'){
|
|
|
|
|
inEvent = null;
|
|
|
|
|
if(this.isInEvent('inspect')){
|
|
|
|
|
this.clearEvent();
|
|
|
|
|
this.drawBoard();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
startAttack(itemAttacking){
|
|
|
|
|
// Selects the card that will be attacking
|
|
|
|
|
// Rename to attack intent?
|
|
|
|
|
|
|
|
|
|
// Do error/legal checks here
|
|
|
|
|
if(cardStatus[itemAttacking] == 'tapped'){
|
|
|
|
|
if(this.isTapped(itemAttacking)){
|
|
|
|
|
alert('Cannot attack, as tapped');
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Set event
|
|
|
|
|
inEvent = ['attack', itemAttacking];
|
|
|
|
|
// Set the status of card to attacking for drawing.
|
|
|
|
|
// TODO:In future this may be what's used for check (or other in case you can attack with multiple units at once)
|
|
|
|
|
cardStatus[itemAttacking] = 'attacking';
|
|
|
|
|
this.setEvent('attack', itemAttacking);
|
|
|
|
|
// TODO:In future this MAY be what's used for check
|
|
|
|
|
this.setCardStatus(itemAttacking, 'attacking');
|
|
|
|
|
|
|
|
|
|
this.drawBoard();
|
|
|
|
|
}
|
|
|
|
|
setEvent(eventName, itemInEvent){
|
|
|
|
|
// TODO: Think this may need a better name
|
|
|
|
|
inEvent = [eventName, itemInEvent];
|
|
|
|
|
}
|
|
|
|
|
clearEvent(){
|
|
|
|
|
inEvent = null;
|
|
|
|
|
}
|
|
|
|
|
setCardStatus(itemToUpdate, newStatus = null){
|
|
|
|
|
// TODO: Check if valid status change, if not ignore
|
|
|
|
|
cardStatus[itemToUpdate] = newStatus;
|
|
|
|
|
}
|
|
|
|
|
// Do the attack
|
|
|
|
|
makeAttack(itemDefending, itemAttacking = null){
|
|
|
|
|
// TODO: Check if mana owner has any 'block', etc. first, then prevent if so
|
|
|
|
|
@ -695,7 +591,7 @@ class Board{
|
|
|
|
|
itemAttacking = inEvent[1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(cardStatus[itemAttacking] == 'tapped'){
|
|
|
|
|
if(this.isTapped(itemAttacking)){
|
|
|
|
|
alert('Cannot attack, as tapped');
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@ -704,8 +600,8 @@ class Board{
|
|
|
|
|
// If card on 'board' attacked
|
|
|
|
|
// Compare attackingCard and defendingCard
|
|
|
|
|
case 'board':
|
|
|
|
|
let atkAttacker = cardData[itemAttacking];
|
|
|
|
|
let atkDefender = cardData[itemDefending];
|
|
|
|
|
let atkAttacker = this.attackOf(itemAttacking);
|
|
|
|
|
let atkDefender = this.attackOf(itemDefending);
|
|
|
|
|
|
|
|
|
|
// Does Attacker kill Defender
|
|
|
|
|
if(atkDefender <= atkAttacker){
|
|
|
|
|
@ -725,11 +621,10 @@ class Board{
|
|
|
|
|
|
|
|
|
|
case 'shield':
|
|
|
|
|
// If the shield is tapped 'destroy' it
|
|
|
|
|
if(cardStatus[itemDefending] == 'tapped'){
|
|
|
|
|
// Remove from shield, add to hand
|
|
|
|
|
// Untap, add to hand (when moving item between status, ANY ITEM. remove status)
|
|
|
|
|
if(this.isTapped(itemDefending)){
|
|
|
|
|
this.destroyShield(itemDefending);
|
|
|
|
|
}
|
|
|
|
|
// Otherwise tap the shield, so it can be destroyed in future
|
|
|
|
|
else{
|
|
|
|
|
this.tapCard(itemDefending);
|
|
|
|
|
}
|
|
|
|
|
@ -742,6 +637,10 @@ class Board{
|
|
|
|
|
|
|
|
|
|
this.drawBoard();
|
|
|
|
|
}
|
|
|
|
|
attackOf(itemKey){
|
|
|
|
|
// TODO: Change this to ECSey element when added
|
|
|
|
|
return cardData[itemKey];
|
|
|
|
|
}
|
|
|
|
|
endAttackFor(itemAttacking){
|
|
|
|
|
// Tap the card (this would check if after attack cards taps or not.
|
|
|
|
|
this.tapCard(itemAttacking);
|
|
|
|
|
@ -762,38 +661,30 @@ class Board{
|
|
|
|
|
this.drawBoard();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Like everything else, need to consolidate into one function that
|
|
|
|
|
// can work for both players, and even more for 2v2 3v1 combats, etc.
|
|
|
|
|
playShield(fromPosition, fromElement, playerId, cardsToPlay = 1){
|
|
|
|
|
for(let shieldNo = 0; shieldNo < cardsToPlay; shieldNo++){
|
|
|
|
|
// Check there's space for shield TODO: change to locationTo
|
|
|
|
|
// TODO: Normalise this for all element/player combos
|
|
|
|
|
let elementLength = getCurrentPositionAndLength('shield', playerId)[1];
|
|
|
|
|
if(elementLength >= maxShield){
|
|
|
|
|
alert('Shield full '+elementLength+'/'+maxShield);
|
|
|
|
|
// Kill loop if there's too many shiled already, no need re-notifying
|
|
|
|
|
return 0;
|
|
|
|
|
let shieldLength = this.shieldCount(playerId);
|
|
|
|
|
// Check shield zone isn't already full
|
|
|
|
|
if(shieldLength >= maxShield){
|
|
|
|
|
alert('Shield full '+shieldLength+'/'+maxShield);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Move from player, position 0 (top) of deck, to hand (next available position)
|
|
|
|
|
this.addFromBoardElement(playerId, fromPosition, fromElement, 'shield', null, null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
shieldCount(playerId){
|
|
|
|
|
return getCurrentPositionAndLength('shield', playerId)[1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
playMana(fromPosition, fromElement, fromPlayer, cardsToPlay = 1){
|
|
|
|
|
// Move from player0, fromPosition of hand (for now), to mana
|
|
|
|
|
// TODO: FOR ALL addFromBoardElements, if 'fromPosition' not passed get the
|
|
|
|
|
// fromPosition and boardElementFrom from the itemId (will need to change to pass this)
|
|
|
|
|
console.log('playMana('+fromPosition+','+fromElement+','+cardsToPlay+')');
|
|
|
|
|
playMana(fromPosition, fromElement, fromPlayer){
|
|
|
|
|
this.addFromBoardElement(fromPlayer, fromPosition, fromElement, 'mana', null, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// HELPER METHODS, to simplify code-base for me in the future
|
|
|
|
|
destroyShield(itemKey){
|
|
|
|
|
// Adds from 'shield' to 'hand' boardElement
|
|
|
|
|
// Sets the listPosition to the next in line for new boardElement
|
|
|
|
|
// Changes the listPosition of each item in previous boardElement
|
|
|
|
|
// All for same player, although below playerFrom/playerTo can be set to switch between players
|
|
|
|
|
// Adds from 'shield' to 'hand' boardElement for player shield belongs to
|
|
|
|
|
|
|
|
|
|
// TODO:Check if shield can be destroyed (instantly, i.e. poisontouch, or some mechanic/spell akin)
|
|
|
|
|
|
|
|
|
|
@ -808,16 +699,19 @@ class Board{
|
|
|
|
|
for(let item = 0; item < items.length; item++){
|
|
|
|
|
let itemKey = items[item];
|
|
|
|
|
// If ANY of their shields are untapped, you can't destroy target
|
|
|
|
|
if(cardStatus[itemKey] != 'tapped'){
|
|
|
|
|
if(!board.isTapped(itemKey)){
|
|
|
|
|
alert('There is an untapped shield, cannot destroy target');
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Shield is now destroyed, move it from shield to owners hand (for the catchup mechanic)
|
|
|
|
|
this.addFromBoardElement(player[itemKey], listPosition[itemKey], boardElement[itemKey], 'hand', null, null);
|
|
|
|
|
this.addShieldToHand(player[itemKey], listPosition[itemKey]);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
addShieldToHand(playerFrom = null, listPositionFrom = null){
|
|
|
|
|
this.addFromBoardElement(playerFrom, listPositionFrom, 'shield', 'hand', null, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sendToGrave(itemKey){
|
|
|
|
|
console.log('SendToGrave: '+itemKey);
|
|
|
|
|
@ -830,10 +724,12 @@ class Board{
|
|
|
|
|
cardStatus[itemKey] = 'tapped';
|
|
|
|
|
// Do any other 'on tap' effects, etc. in the future
|
|
|
|
|
}
|
|
|
|
|
tap(itemKey){ tapCard(itemKey); }
|
|
|
|
|
untapCard(itemKey){
|
|
|
|
|
cardStatus[itemKey] = null;
|
|
|
|
|
// Do any other 'on tap' effects, etc. in the future
|
|
|
|
|
}
|
|
|
|
|
untap(itemKey){ untapCard(itemKey); }
|
|
|
|
|
remainingShieldCount(playerId){
|
|
|
|
|
return getCurrentPositionAndLength('shield', playerId)[1];
|
|
|
|
|
}
|
|
|
|
|
@ -845,21 +741,24 @@ class Board{
|
|
|
|
|
if(cardStatus[itemKey] == 'tapped'){ return true; }
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
isAttacking(itemKey){
|
|
|
|
|
if(cardStatus[itemKey] == 'attacking'){ return true; }
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Run board commands here for testing
|
|
|
|
|
let board = new Board;
|
|
|
|
|
|
|
|
|
|
// TODO: TEMP!! Replace soon
|
|
|
|
|
createDeck();
|
|
|
|
|
//createDeckList(playerDeck, deckCount, 0);
|
|
|
|
|
//createDeckList(opponentDeck, deckCountOpponent, 1);
|
|
|
|
|
// Fill each players deck with their cards
|
|
|
|
|
createDecks();
|
|
|
|
|
|
|
|
|
|
// Play 4 shield from top (0) of each players deck
|
|
|
|
|
// Play shield from top of each players deck to the maximum allowed (4 typically)
|
|
|
|
|
for(let currentPlayer = 0; currentPlayer <= players-1; currentPlayer++){
|
|
|
|
|
board.playShield(1, 'deck', currentPlayer, 4);
|
|
|
|
|
board.playShield(1, 'deck', currentPlayer, maxShield);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw the graphics of the board/game
|
|
|
|
|
board.drawBoard(true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -882,7 +781,7 @@ canvas.addEventListener('contextmenu', function(event) {
|
|
|
|
|
// Check the item has a size and position
|
|
|
|
|
if(itemKey in size && itemKey in position){
|
|
|
|
|
// Compare the event XY position to the item
|
|
|
|
|
if(clickableCheck(x,y,false,itemKey)){
|
|
|
|
|
if(clickableCheck(x,y,itemKey)){
|
|
|
|
|
// Only want to happen once (for now)
|
|
|
|
|
// Maybe in future add to hand would trigger another event if there's an effect?
|
|
|
|
|
|
|
|
|
|
@ -898,7 +797,7 @@ canvas.addEventListener('contextmenu', function(event) {
|
|
|
|
|
// If there's an attack event, target other cards
|
|
|
|
|
// If there is an event, the event is attack event, and the item currently loop
|
|
|
|
|
// is the same one as currently in the event
|
|
|
|
|
if(inEvent && inEvent[0] == 'attack' && itemKey == inEvent[1]){
|
|
|
|
|
if(board.isInEvent('attack') && itemKey == inEvent[1]){
|
|
|
|
|
board.cancelAttackFor(itemKey);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
@ -948,7 +847,7 @@ canvas.addEventListener('click', function(event) {
|
|
|
|
|
// Check the item has a size and position
|
|
|
|
|
if(itemKey in size && itemKey in position){
|
|
|
|
|
// Compare the event XY position to the item
|
|
|
|
|
if(clickableCheck(x,y,false,itemKey)){
|
|
|
|
|
if(clickableCheck(x,y,itemKey)){
|
|
|
|
|
// Only want to happen once (for now)
|
|
|
|
|
// Maybe in future add to hand would trigger another event if there's an effect?
|
|
|
|
|
|
|
|
|
|
@ -974,7 +873,7 @@ canvas.addEventListener('click', function(event) {
|
|
|
|
|
// yourPlayerId in for now to prevent using opponents card
|
|
|
|
|
// TODO:the cards may be used to attack, there will be another
|
|
|
|
|
// check like 'canUseOpponentsBoard' or something
|
|
|
|
|
if(!inEvent && cardStatus[itemKey] != 'tapped' && playerId == yourPlayerId){
|
|
|
|
|
if(!inEvent && !board.isTapped(itemKey) && playerId == yourPlayerId){
|
|
|
|
|
board.startAttack(itemKey);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@ -1025,34 +924,25 @@ canvas.addEventListener('click', function(event) {
|
|
|
|
|
|
|
|
|
|
}, false);
|
|
|
|
|
|
|
|
|
|
function clickableCheck(x,y,clickable=false,itemKey=false){
|
|
|
|
|
function clickableCheck(cursorX,cursorY,itemKey){
|
|
|
|
|
// Collision detection between clicked offset and clickableItems
|
|
|
|
|
// https://stackoverflow.com/a/9880302
|
|
|
|
|
|
|
|
|
|
// Temp solution to add the check while the old way also exists
|
|
|
|
|
// simultaneously. It works, so that's nice
|
|
|
|
|
if(clickable === false && itemKey !== false){
|
|
|
|
|
clickable = {};
|
|
|
|
|
//console.log(clickable);
|
|
|
|
|
//console.log(itemKey);
|
|
|
|
|
clickable.x = position[itemKey][0];
|
|
|
|
|
clickable.y = position[itemKey][1];
|
|
|
|
|
clickable.width = size[itemKey][0];
|
|
|
|
|
clickable.height = size[itemKey][1];
|
|
|
|
|
//console.log(clickable);
|
|
|
|
|
}
|
|
|
|
|
let itemX = position[itemKey][0];
|
|
|
|
|
let itemY = position[itemKey][1];
|
|
|
|
|
let itemWidth = size[itemKey][0];
|
|
|
|
|
let itemHeight = size[itemKey][1];
|
|
|
|
|
|
|
|
|
|
// Debug Stuff
|
|
|
|
|
let debug = false
|
|
|
|
|
if(debug){
|
|
|
|
|
console.log(clickable.y+' <');
|
|
|
|
|
console.log(y+ '<')
|
|
|
|
|
console.log(clickable.y+clickable.height);
|
|
|
|
|
console.log(itemY+' <');
|
|
|
|
|
console.log(cursorY+ '<')
|
|
|
|
|
console.log(itemY+itemHeight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(
|
|
|
|
|
y > clickable.y && y < clickable.y + clickable.height
|
|
|
|
|
&& x > clickable.x && x < clickable.x + clickable.width)
|
|
|
|
|
cursorY > itemY && cursorY < itemY + itemHeight
|
|
|
|
|
&& cursorX > itemX && cursorX < itemX + itemWidth)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
@ -1061,7 +951,7 @@ function clickableCheck(x,y,clickable=false,itemKey=false){
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createDeck(){
|
|
|
|
|
function createDecks(){
|
|
|
|
|
// Create a 'realDeck' element for each player
|
|
|
|
|
for(let i = 0; i < players; i++){
|
|
|
|
|
item.push(itemCount);
|
|
|
|
|
@ -1132,15 +1022,9 @@ function shuffleDeck(playerId){
|
|
|
|
|
let items = board.getItems('deck', playerId, null, null);
|
|
|
|
|
for(let item = 0; item < items.length; item++){
|
|
|
|
|
let itemKey = items[item];
|
|
|
|
|
//console.log('ITEM KEY: '+itemKey);
|
|
|
|
|
//console.log('OLD LIST POSITION: '+listPosition[itemKey]);
|
|
|
|
|
|
|
|
|
|
listPosition[itemKey] = tempDeck[item];
|
|
|
|
|
|
|
|
|
|
//console.log('NEW LIST POSITION: '+listPosition[itemKey]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function untapZone(elementFrom, playerFrom){
|
|
|
|
|
@ -1156,7 +1040,6 @@ function untapAllZones(currentPlayer = null){
|
|
|
|
|
currentPlayer = 0;
|
|
|
|
|
}
|
|
|
|
|
for(let currentPlayer = 0; currentPlayer <= players-1; currentPlayer++){
|
|
|
|
|
let elements = ['deck','board','hand','mana','shield', 'grave'];
|
|
|
|
|
// Loop all the elements, and utap each card in the zone
|
|
|
|
|
for(let element = 0; element < elements.length; element++){
|
|
|
|
|
untapZone(elements[element], currentPlayer);
|
|
|
|
|
@ -1177,11 +1060,9 @@ function getCurrentPositionAndLength(elementName, playerId){
|
|
|
|
|
highestListPosition = listPosition[itemKey];
|
|
|
|
|
}
|
|
|
|
|
length++;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [highestListPosition, length];
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function calculateItemSizePosition(itemKey){
|
|
|
|
|
|