Merge branch 'feature/serverSideItems' into develop
commit
90de381d69
@ -0,0 +1,450 @@
|
||||
// Need to require DB again. Apparently this is ok, as it'll
|
||||
// still only have one require cross project (?)
|
||||
const database = require('./database');
|
||||
|
||||
|
||||
// cardClass, cardColourRequirement
|
||||
// may want to be seperate too (as well as in cardItem), so that
|
||||
// during match they can be altered by effects while keeping the OG card
|
||||
// for inspecting (and compare against new stats,reqs,etc.)
|
||||
// same with attack, cost, etc. things that will can be visually shown as
|
||||
// changed in game
|
||||
|
||||
// Just grabbing everything from DB for now, as it's quite small at current
|
||||
// then will rejig when needed.
|
||||
// Should all cards, effects, classes etc. be loaded in on server start
|
||||
// then just load decks and decklists when needed?
|
||||
function getDecks(deckIds = false){
|
||||
// Await promise, once it's done get the data, if errors send err
|
||||
const dPromise = new Promise((resolve, reject) => {
|
||||
|
||||
database.dbGetDecks().then(data => {
|
||||
|
||||
let decks = [];
|
||||
|
||||
data.forEach((deck) => {
|
||||
//let itemId = item.length;
|
||||
//item.push(itemId); // Add the next available item
|
||||
// Add the deck info to deckItem
|
||||
// deckItem[itemId] = {};
|
||||
decks.push({
|
||||
'deckId': deck.deckId,
|
||||
'playerId': deck.playerId,
|
||||
'deckName': deck.deckName,
|
||||
});
|
||||
});
|
||||
|
||||
// Resolve the decks pulled
|
||||
resolve(decks);
|
||||
|
||||
//console.log(item);
|
||||
//console.log(deckItem);
|
||||
//console.log(decks);
|
||||
})
|
||||
.catch(err => { throw err; })
|
||||
|
||||
});
|
||||
return dPromise;
|
||||
}
|
||||
//getDecks();
|
||||
function getDeckList(){
|
||||
const dPromise = new Promise((resolve, reject) => {
|
||||
|
||||
database.dbGetDeckList().then(data => {
|
||||
|
||||
let deckList = [];
|
||||
|
||||
data.forEach((listItem) => {
|
||||
// Add the deck info to deckItem
|
||||
deckList.push({
|
||||
'deckId': listItem.deckId,
|
||||
'playerId': listItem.playerId,
|
||||
'cardId': listItem.cardId,
|
||||
'cardCount': listItem.cardCount,
|
||||
});
|
||||
resolve(deckList);
|
||||
});
|
||||
})
|
||||
.catch(err => { throw err; })
|
||||
});
|
||||
return dPromise;
|
||||
}
|
||||
//getDeckList();
|
||||
function getCards(){
|
||||
const dPromise = new Promise((resolve, reject) => {
|
||||
|
||||
database.dbGetCards().then(data => {
|
||||
|
||||
let cards = [];
|
||||
|
||||
data.forEach((card) => {
|
||||
cards.push({
|
||||
'id': card.id,
|
||||
'cardName': card.cardName,
|
||||
'cardCost': card.cardCost,
|
||||
'cardType': card.cardType,
|
||||
'cardAttack': card.cardAttack,
|
||||
'cardRarity': card.cardRarity,
|
||||
'cardClass': [],
|
||||
'cardColourRequirement': [],
|
||||
});
|
||||
});
|
||||
resolve(cards);
|
||||
})
|
||||
.catch(err => { throw err; })
|
||||
|
||||
});
|
||||
return dPromise;
|
||||
}
|
||||
//getCards();
|
||||
function getCardClasses(){
|
||||
const dPromise = new Promise((resolve, reject) => {
|
||||
database.dbGetCardClasses().then(data => {
|
||||
|
||||
let cardClasses = [];
|
||||
|
||||
data.forEach((cardClass) => {
|
||||
|
||||
cardClasses.push({
|
||||
'cardId': cardClass.cardId,
|
||||
'classId': cardClass.classId,
|
||||
});
|
||||
|
||||
});
|
||||
resolve(cardClasses);
|
||||
})
|
||||
.catch(err => { throw err; })
|
||||
});
|
||||
return dPromise;
|
||||
}
|
||||
//getCardClasses();
|
||||
function getCardColourRequirement(){
|
||||
const dPromise = new Promise((resolve, reject) => {
|
||||
database.dbGetCardColourRequirement().then(data => {
|
||||
|
||||
let colourRequirements = [];
|
||||
|
||||
data.forEach((cardColourReq) => {
|
||||
|
||||
colourRequirements.push({
|
||||
'cardId': cardColourReq.cardId,
|
||||
'colourId': cardColourReq.colourId,
|
||||
'cost': cardColourReq.cost,
|
||||
});
|
||||
|
||||
});
|
||||
resolve(colourRequirements);
|
||||
|
||||
})
|
||||
.catch(err => { throw err; })
|
||||
});
|
||||
return dPromise;
|
||||
}
|
||||
//getCardColourRequirement();
|
||||
// Then effects which will have effects with parent triggers, and unit type checks
|
||||
// colour checks, all sorts. So will be more difficult. Basic (flight, etc)
|
||||
// shouldn't be too bad
|
||||
// something like effect_basic, card_effect, effect_trigger, effect_requirement, effect_option
|
||||
// effect_stage, effect_advanced, with advanced being an id with x triggers, triggers have
|
||||
// x req, advanced as with x options, x stages to be able to fine-tune fancy stuff
|
||||
// combining all other effects, units, cards, colours, etc. Will be a lot of though,
|
||||
// but better than hard coding anything more than basic effects and effect check logic
|
||||
// TODO: effect (as above)
|
||||
|
||||
// request a deck in the format CURRENTLY used in the game
|
||||
// decks will likely be changed around
|
||||
|
||||
// https://www.geeksforgeeks.org/how-to-wait-for-multiple-promises-in-javascript/
|
||||
// https://medium.com/@nikolozz/using-socket-io-with-async-await-13fa8c2dc9d9
|
||||
// using last example
|
||||
// TODO: When this is functionally working, need to split up into other func/modules
|
||||
// such as: playerMod, cardMod, deckMod, miscMod ?
|
||||
function requestDeck(itemData = null){
|
||||
return new Promise((resolve, reject) => {
|
||||
(async () => {
|
||||
|
||||
// Get the deck(s) requested.
|
||||
// Not 100% on how to do two differening atm
|
||||
// Besides all of playerId, and all of deckId. But 1,2/2,3 for instance
|
||||
const [decks, deckList] =
|
||||
await Promise.all([
|
||||
getDecks(),
|
||||
getDeckList()
|
||||
]);
|
||||
|
||||
//console.log(decks);
|
||||
//console.log(deckList);
|
||||
// Now loop the deckList for the cardIds
|
||||
let deckCardIds = [];
|
||||
deckList.forEach((deckItem) => {
|
||||
deckCardIds.push(deckItem.cardId);
|
||||
|
||||
});
|
||||
//console.log(deckCardIds);
|
||||
|
||||
// Next, get the cards in the deck by their ID
|
||||
// TODO: https://stackoverflow.com/a/65510676
|
||||
// Change SQL to accept for just the cards passed
|
||||
|
||||
// Get each cards data, colourReqs, and classes
|
||||
const [cards, cardClasses, cardColourRequirements] =
|
||||
await Promise.all([
|
||||
getCards(),
|
||||
getCardClasses(),
|
||||
getCardColourRequirement(),
|
||||
]);
|
||||
// ^^^^ 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
|
||||
|
||||
// TODO: Build the card so far async for it's done alongside getting effects?
|
||||
// Then when both done add the effects to the existing cardObjects? Yep good idea me
|
||||
//console.log(cards);
|
||||
//console.info(cardClasses);
|
||||
//console.log(cardColourRequirements);
|
||||
|
||||
const [builtCards] =
|
||||
await Promise.all([
|
||||
buildCards(cards, cardClasses, cardColourRequirements),
|
||||
// TODO: builtEffects
|
||||
]);
|
||||
|
||||
//console.log(builtCards);
|
||||
// TODO: addEffectsToCards
|
||||
// TODO: Finally do the effects for each card. This will be the complicater
|
||||
// since it's not 100% thought out yet... (
|
||||
|
||||
// Add the cards (x of how many cardObjects with cardId are in count in decklist)
|
||||
// to a deck array to pass through. Or decks array with deckId specified?
|
||||
//console.log(deckList);
|
||||
// These are the four basic fellas for this
|
||||
// from public/board.js where current game testing/logic is applied
|
||||
// So creating as a test for a 'room' to see if it's simple enough to
|
||||
// send and play with
|
||||
// BUILD THE DATA TO SEND TO CLIENTS! (Kinda)
|
||||
|
||||
// To continue from previous item/itemCount from other funcs, something like this
|
||||
let item = [];
|
||||
let itemCount = 0;
|
||||
let player = {};
|
||||
let players = [];
|
||||
|
||||
// Jank check to allow current client call, and new roomMod.roomGeneration call to
|
||||
// both work (will replace client call with roomGeneration when closer)
|
||||
if(itemData !== null){
|
||||
if(itemData['item'] !== undefined){
|
||||
item = itemData['item'];
|
||||
}
|
||||
if(itemData['itemCount'] !== undefined){
|
||||
itemCount = itemData['itemCount'];
|
||||
}
|
||||
if(itemData['player'] !== undefined){
|
||||
player = itemData['player'];
|
||||
}
|
||||
if(itemData['players'] !== undefined){
|
||||
players = itemData['players'];
|
||||
}
|
||||
}else{
|
||||
itemData = {};
|
||||
}
|
||||
|
||||
// TODO: Deck data/deckIn should be in deckGen, other stuff probably in a cardGen
|
||||
// function
|
||||
let deckData = {}; // New but may be useful
|
||||
let deckIn = {}; // Which deck the item is in? Kinda the player/boardelement thing?
|
||||
let cardData = {};
|
||||
let boardElement = {};
|
||||
// New(in here)
|
||||
let cardStatus = {}; // Tapped, etc
|
||||
// player
|
||||
let listPosition = {};
|
||||
let cardFace = {};
|
||||
// REALLY NEW
|
||||
let cardColours = {}; // Array of req.
|
||||
let cardAttack = {}; // Base, Current
|
||||
let cardSprite = {}; // Maybe from DB?
|
||||
|
||||
// TODO: Set the player. For now will do this in front-end as testing currently
|
||||
|
||||
let forPlayer = 0; // TODO: Change to actually have each player select a deck
|
||||
// Loop and create the deck first
|
||||
decks.forEach((deck) => {
|
||||
item.push(itemCount); // Add new item to add stuff for
|
||||
deckData[itemCount] = {'deckId':deck.deckId, 'playerId':deck.playerId, 'deckName':deck.deckName, 'maxLength': 0}; // Max length for listPositioning later in cardBuild
|
||||
boardElement[itemCount] = 'realDeck';
|
||||
cardFace[itemCount] = 0; // Face down for deck
|
||||
player[itemCount] = forPlayer;
|
||||
itemCount++; // Needed/good
|
||||
forPlayer++; // Jank/bad
|
||||
})
|
||||
//console.log(deckData);
|
||||
//console.log(deckList);
|
||||
|
||||
// Loop each item in the deckList
|
||||
// Loop inside it X times where X is cardCount
|
||||
// Add the builtCard with same cardId as deckList item X times
|
||||
|
||||
// and load that deck for them. This just sets first deck to player0 to players.length
|
||||
deckList.forEach((deckListItem) => {
|
||||
|
||||
let deckItem = null;
|
||||
// Loop each deck, if the deck/playerIds match, add association
|
||||
for(key in deckData){
|
||||
//Object.keys(deckData).forEach(function(key) { // Less efficient than for
|
||||
// Needs to check deck AND player id, as that's the primary key (together)
|
||||
if(deckData[key].deckId == deckListItem.deckId && deckData[key].playerId == deckListItem.playerId){
|
||||
deckItem = key; // Key is the `item` key
|
||||
// Now add cards to the player that this deck belongs to
|
||||
forPlayer = player[key];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// For each new card, loop to the cardCount (how many cards in deck)
|
||||
// and add to the deck
|
||||
for(let i = 0; i < deckListItem.cardCount; i++){
|
||||
item.push(itemCount); // Add new item to add stuff for
|
||||
// ^ not using item.length incase anything in future gets deleted
|
||||
// from item for instance
|
||||
cardData[itemCount] = builtCards[deckListItem.cardId]; // builtCards id set to cardId from DB, so adding the builtCard object is based on the deckList's cardId (from DB)
|
||||
boardElement[itemCount] = 'deck'; // Add all cards to deck at match start
|
||||
// Associate the card with the deck
|
||||
// TODO: Change deckIn to something more sensical
|
||||
deckIn[itemCount] = deckItem;
|
||||
|
||||
// Attempt to set the listPosition of each card in related deck
|
||||
// Increase the length of the deck in deckItem
|
||||
listPosition[itemCount] = deckData[deckItem].maxLength; // TODO: better
|
||||
deckData[deckItem].maxLength++;
|
||||
|
||||
// Adding to get everything sorted in one!
|
||||
cardStatus[itemCount] = null;
|
||||
cardFace[itemCount] = 0; // Face down by default (in deck)
|
||||
cardColours[itemCount] = cardData[itemCount].colourRequirements; // TODO;
|
||||
// From cardData set the base attack, and current (same when deckbuild)
|
||||
let atk = cardData[itemCount].atk;
|
||||
cardAttack[itemCount] = [atk, atk]; // Base, Current
|
||||
player[itemCount] = forPlayer; // Jank TODO: actually set to correct player
|
||||
|
||||
|
||||
itemCount++; // Increment item to not overwrite
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// ADD all new elements, and updated data into itemData
|
||||
itemData.item = item;
|
||||
itemData.itemCount = itemCount;
|
||||
itemData.player = player;
|
||||
itemData.players = players;
|
||||
itemData.deckData = deckData;
|
||||
itemData.deckIn = deckIn;
|
||||
itemData.cardData = cardData;
|
||||
itemData.boardElement = boardElement;
|
||||
itemData.cardStatus = cardStatus;
|
||||
itemData.listPosition = listPosition;
|
||||
itemData.cardFace = cardFace;
|
||||
itemData.cardColours = cardColours;
|
||||
itemData.cardAttack = cardAttack;
|
||||
itemData.cardSprite = cardSprite;
|
||||
|
||||
// item, itemCount, deckData, cardData, boardElement
|
||||
//console.log(cardData);
|
||||
|
||||
// Returning everything to be looped in the front-end
|
||||
// This won't be looped as it will at final, instead just for deck generation
|
||||
// Returned as object over array, as easier to disect when gets to front-end
|
||||
let dataReturn = itemData;
|
||||
return resolve(dataReturn);
|
||||
//return resolve(cardData);
|
||||
|
||||
// Promise stuff testing
|
||||
})()
|
||||
});
|
||||
|
||||
// TODO: In future the item inc. all the decks, cards, locations, and other attributes
|
||||
// will come from here
|
||||
|
||||
// TODO: unrelated, but thought. If lots of players on, generating cards each time
|
||||
// will be a big hit, as well as all the DB hits, so may need to load all cardObjects
|
||||
// into memory/array when server starts. This then prevents any DB changes to alter
|
||||
// things, but outside of testing that won't occur(?), may need to test this at some
|
||||
// point to see. For now DB, and generating is ok, as still working on it
|
||||
}
|
||||
|
||||
function buildCards(cards, cardClasses, cardColourRequirements){
|
||||
|
||||
console.log(cardColourRequirements);
|
||||
const dPromise = new Promise((resolve, reject) => {
|
||||
|
||||
builtCards = {};
|
||||
|
||||
//console.log(cards);
|
||||
// Loop the cards and build the base
|
||||
cards.forEach((card) => {
|
||||
|
||||
let builtCard = {
|
||||
id: card.id,
|
||||
name: card.cardName,
|
||||
colour: [],
|
||||
cost: card.cardCost,
|
||||
colourRequirements: [],
|
||||
type: card.cardType,
|
||||
atk: card.cardAttack,
|
||||
rarity: card.cardRarity,
|
||||
effect: [],
|
||||
cardClass: [],
|
||||
};
|
||||
// Give the card an easily accessible Id for compares
|
||||
// and to add to the cardItem being built
|
||||
builtCards[card.id] = builtCard;
|
||||
|
||||
});
|
||||
//console.log(builtCards);
|
||||
|
||||
// Next loop each class, and add to the new builtCard (if cardIds match)
|
||||
cardClasses.forEach((cardClass) => {
|
||||
|
||||
// Check the card exists (it should always, but don't want jank)
|
||||
if(cardClass.cardId in builtCards){
|
||||
// It's the Id for now
|
||||
// TODO: Send the text too (from join) but don't use for compares
|
||||
//console.log(cardClass.cardId);
|
||||
//console.log(cardClass.classId);
|
||||
//console.log('---');
|
||||
//console.log(builtCards[cardClass.cardId]);
|
||||
|
||||
// Add the class to the class array (cards can have multiple)
|
||||
builtCards[cardClass.cardId].cardClass.push(cardClass.classId);
|
||||
|
||||
// TODO: As an array [classId, className] then
|
||||
// card.classes[x][0] can be compared as numeric in code
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Do the same for cardColourRequirements (if cardIds match)
|
||||
cardColourRequirements.forEach((colourReq) => {
|
||||
|
||||
// Check the card exists (it should always, but don't want jank)
|
||||
if(colourReq.cardId in builtCards){
|
||||
// Add the colours to the class array (cards can have multiple)
|
||||
builtCards[colourReq.cardId].colourRequirements.push([colourReq.colourId, colourReq.cost]);
|
||||
|
||||
// TODO: As an array [classId, className] then
|
||||
// card.classes[x][0] can be compared as numeric in code
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
resolve(builtCards);
|
||||
|
||||
});
|
||||
return dPromise;
|
||||
}
|
||||
// TODO: Add the effects onto the cards passed through
|
||||
// Takes cards array (of obj), and array of effects (from DB or built, probabaly pre-built?)
|
||||
function addCardsEffects(){}
|
||||
|
||||
module.exports = {
|
||||
requestDeck
|
||||
};
|
||||
@ -0,0 +1,71 @@
|
||||
// Build a room, fill will players, etc.
|
||||
const cardGen = require('./cardGen');
|
||||
|
||||
|
||||
// Room should, setPlayers, add them to correct team (TODO), build their decks, and first shuffle
|
||||
|
||||
function startItemCount(){
|
||||
let item = [];
|
||||
let itemCount = 0;
|
||||
|
||||
returns = {'item': item, 'itemCount': itemCount};
|
||||
return(returns);
|
||||
}
|
||||
function setPlayers(playerCount = 2, itemData){
|
||||
// Add new item attribute for 'players'
|
||||
// TODO: Maybe check if exists, and add to in that case (for replacing people?)
|
||||
// Doubt that would ever make it into the game, but could still be worth
|
||||
itemData.player = {}; //let player = {}; // Player item belongs to
|
||||
itemData.players = []; // List of the players (an associated playerItem?)
|
||||
//itemData.
|
||||
|
||||
// Can be done with just referring to itemData[x], but less readable
|
||||
// Will likely redefine vars each new function. For now will keep this as-is
|
||||
|
||||
let playerNo = 0 + itemData['itemCount']; // Start loop from current itemCount
|
||||
playerCount = playerCount + itemData['itemCount']; // End at playerCount diff from itemCount
|
||||
for(playerNo; playerNo < playerCount; playerNo++){
|
||||
// REMOVED PLAYERS AS ITEM, BECAUSE THEY WERE BORKING
|
||||
// TODO: Add back at some point, or don't bother
|
||||
//itemData['item'].push(playerNo);
|
||||
//itemData['player'][itemData['itemCount']] = playerNo; // The player belongs to itself
|
||||
//itemData['itemCount']++;
|
||||
itemData['players'].push(playerNo); // Add player no to array so can be looped
|
||||
}
|
||||
// Return related item and item attributes
|
||||
//returns = {'item': item, 'itemCount': itemCount, 'player': player};
|
||||
return itemData;
|
||||
//return([item, itemCount, player]);
|
||||
}
|
||||
|
||||
// For future, when 2v2s, and 5v1 Raids, etc.
|
||||
function setTeams(){
|
||||
|
||||
}
|
||||
|
||||
function roomGeneration(playerCount, teamCount = null, playerTeams = null){
|
||||
return new Promise((resolve, reject) => {
|
||||
(async () => {
|
||||
let itemData = startItemCount();
|
||||
|
||||
// Create 2 players for the room
|
||||
itemData = setPlayers(2, itemData);
|
||||
|
||||
// TODO: Get their selected decks (will need to pass somewhere)
|
||||
|
||||
// Generate the decks, and card within the deck cardLists
|
||||
[itemData] = await Promise.all([ cardGen.requestDeck(itemData) ]);
|
||||
|
||||
//console.log('deckData');
|
||||
//console.log(deckData);
|
||||
return resolve(itemData);
|
||||
})()
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
startItemCount
|
||||
,setPlayers
|
||||
,roomGeneration
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue