Compare commits

..

No commits in common. 'develop' and 'master' have entirely different histories.

3
.gitignore vendored

@ -1,3 +0,0 @@
package-lock.json
node_modules
node_modules/*

@ -1,39 +0,0 @@
# Card Game
## Technology
- node.js
- express.js
- socketIO
- HTML5 (Canvas)
## Install
`sudo apt install npm`
`git pull <this-repo>`
`npm install express --save`
socketio, mysql
## Run
`node server.js`
Access through
`http://localhost:3000`
### Development
BACKEND/SERVER DEVELOPMENT ONLY
To prevent the exhausting task of restarting the server on change
install and run with nodemon, it'll handle server restart each time
a js file is saved (this does also restart for front-end)
`npm install -g nodemon`
Run with
`nodemon --inspect server.js`

@ -1,677 +0,0 @@
// Need to require DB again. Apparently this is ok, as it'll
// still only have one require cross project (?)
const database = require('./database');
const util = require('util')
// Get the decks requested
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(deckIds).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(deckIds = false){
const dPromise = new Promise((resolve, reject) => {
database.dbGetDeckList(deckIds).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;
}
function getCards(cardIds = false){
const dPromise = new Promise((resolve, reject) => {
database.dbGetCards(cardIds).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;
}
function getCardClasses(cardIds = false){
const dPromise = new Promise((resolve, reject) => {
database.dbGetCardClasses(cardIds).then(data => {
let cardClasses = [];
data.forEach((cardClass) => {
cardClasses.push({
'cardId': cardClass.cardId,
'classId': cardClass.classId,
});
});
resolve(cardClasses);
})
.catch(err => { throw err; })
});
return dPromise;
}
function getCardColourRequirement(cardIds = false){
const dPromise = new Promise((resolve, reject) => {
database.dbGetCardColourRequirement(cardIds).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;
}
function getCardManaColour(cardIds = false){
const cPromise = new Promise((resolve, reject) => {
database.dbGetCardManaColour(cardIds).then(data => {
let manaColours = [];
data.forEach((cardManaColour) => {
manaColours.push({
'cardId': cardManaColour.cardId,
'colourId': cardManaColour.colourId,
});
});
resolve(manaColours);
})
.catch(err => { throw err; })
});
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;
}
// https://www.geeksforgeeks.org/how-to-wait-for-multiple-promises-in-javascript/
// https://medium.com/@nikolozz/using-socket-io-with-async-await-13fa8c2dc9d9
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
// Build array of decks to get
let deckIds = [];
for(let i = 0; i < itemData.players.length; i++){
let deckStuff = itemData.players[i][1].deck;
deckIds.push([deckStuff.playerId, deckStuff.deckId]);
// So should be array of [playerId, deckId] which is primary key in DB
}
// Get said decks, and their deckLists
const [decks, deckList] =
await Promise.all([
getDecks(deckIds),
getDeckList(deckIds)
]);
/*
console.log('--- decks ---');
console.log(decks);
console.log('= deckLists =')
console.log(deckList);
console.log('------');
*/
// Now loop the deckList for the cardIds
let deckCardIds = [];
deckList.forEach((deckItem) => {
deckCardIds.push(deckItem.cardId);
});
// Next, get the cards in the deck by their ID
// TODO: https://stackoverflow.com/a/65510676
// Get each cards data, colourReqs, and classes
const [cards, cardClasses, cardColourRequirements, cardManaColours, cardPassives] =
await Promise.all([
getCards(deckCardIds),
getCardClasses(deckCardIds),
getCardColourRequirement(deckCardIds),
getCardManaColour(deckCardIds),
getCardPassive(deckCardIds),
]);
// Return all effect data from DB
const [effects] =
await Promise.all([
database.dbGetEffect(deckCardIds), // Get effects
]);
// Loop the effects for their effectIds to then get the steps/triggers from DB
let effectIds = [];
await effects.forEach((effect) => {
effectIds.push(effect.effectId);
});
// Then pass the effectIds to get their steps/triggers
const [effectSteps, effectTriggers] =
await Promise.all([
database.dbGetEffectStep(effectIds),
database.dbGetEffectTrigger(effectIds),
]);
/*
console.log('--- Effects ---');
console.log(effects);
*/
// Build Effects
const [cardEffects] =
await Promise.all([
buildCardEffects(effects, effectSteps, effectTriggers),
]);
// cardEffects[0][cardId] == [array of effect IDs]
// cardEffects[1][effectId] == {object of the effect data}
//console.log(cardEffects);
// Build the cardData (maybe do all the components here too)
const [builtCards] =
await Promise.all([
buildCards(cards, cardClasses, cardColourRequirements, cardManaColours, cardEffects, cardPassives),
]);
//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?
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
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
// TODO: Associate player to deck differently (both could be using same deck
// via some kind of 'try a deck' or 'use friends deck' option)
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;
cardManaColour[itemCount] = cardData[itemCount].cardManaColour;
// 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
// 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
}
});
// 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;
itemData.cardManaColour = cardManaColour;
itemData.cardEffect = cardEffect;
itemData.flight = flight;
itemData.reach = reach;
// 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, cardManaColours, cardEffects, cardPassives){
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: [],
cardManaColour: [], // Should probably be an object
type: card.cardType,
atk: card.cardAttack,
rarity: card.cardRarity,
effect: [],
cardClass: [],
passive: [],
};
// 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
}
});
// Add card mana colours (colour value when played in mana zone)
cardManaColours.forEach((manaCol) => {
// Check the card exists (it should always, but don't want jank)
if(manaCol.cardId in builtCards){
// Add the colours to the class array (cards can have multiple)
builtCards[manaCol.cardId].cardManaColour.push(manaCol.colourId);
}
});
// 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);
});
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
};

@ -1,99 +0,0 @@
// A seperate list for components, so they're easy to recall
// Done as object, so it can be added to different rooms with components = NEW component?
const component = {
// Entity Stuff
//item : [],
//itemCount : 0,
roomId : null,
turn : 0,
playerTurn : 0,
// Card Stuff
cardData : {},
cardFace : {},
cardStatus : {
tapped : {},
attacking : {},
inspected : {},
},
cardAttack : {},
cardColours : {}, // Replace with colour
colour : {
white : {}, // entityId, amountOfColour
blue : {},
red : {},
},
cardManaColour : {},
cardEffect : {}, // TODO: Split this into effect, trigger, step, targets.
cardCost : {},
cardSprite : {}, // id, position in spritesheet [0,4] e.g.
//cardPlayer = {},
// Deck Stuff?
deckIn : {},
deckData : {},
// UI (so users know what's been targetted)
selected : {},
selectable : {},
// Effect (break it up?)
effect : {},
effectTrigger : {},
// etc, etc.
// Board Elements
// loop component.shield for shield items
boardElement : {},
// Replace with following
realDeck : {},
inDeck : {},
hand : {},
board : {},
shield : {},
mana : {},
grave : {},
void : {},
//
listPosition : {},
// position (clientside)
// size (clientside)
// Passives
// component.passive.flight ?
passive : {
flight : {},
reach : {},
taunt : {},
},
type : {
unit : {},
spell : {},
token : {},
},
classes : {
orc : {},
human : {},
spirit : {},
},
};
// For front-end
// position, size
// These should be used as such (Not 100% as yet)
// For onBoard()... for player()... for passive.flight()...
// Check the board, items belonging to playerX, for flight passive?
module.exports = {
component
}

@ -1,263 +0,0 @@
const mysql = require('mysql');
const con = mysql.createConnection({
host: "localhost",
user: "realmsdivided",
password: "realmsdivided",
database: "realms_divided"
});
function connect(){
con.connect(function(err) {
if (err) { console.log(err); }
else { console.log('DB Connected'); }
});
}
function disconnect(){
con.end();
}
// My DB stuffs
function dbGetDecks(deckIds = false){
const dPromise = new Promise((resolve, reject) => {
let cards = [];
let sql = `SELECT
deckId
,playerId
,deckName
FROM deck
`;
// TODO: Jank, need to unjank it
if(deckIds){
for(let i = 0; i < deckIds.length; i++){
if(i == 0){ sql += ' WHERE '; }
else{ sql += ' OR '; }
sql += '(deckId = '+deckIds[i][1]+' AND playerId = '+deckIds[i][0]+')';
}
}
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
resolve(result);
});
});
return dPromise;
}
function dbGetDeckList(deckIds = false){
const dPromise = new Promise((resolve, reject) => {
let cards = [];
let sql = `SELECT
deckId
,playerId
,cardId
,cardCount
FROM deck_cards
`;
// TODO: Jank, need to unjank it
if(deckIds){
for(let i = 0; i < deckIds.length; i++){
if(i == 0){ sql += ' WHERE '; }
else{ sql += ' OR '; }
sql += '(deckId = '+deckIds[i][1]+' AND playerId = '+deckIds[i][0]+')';
}
}
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
resolve(result);
});
});
return dPromise;
}
function dbGetCards(cardIds = false){
// Start with basic stuff in card table
const dPromise = new Promise((resolve, reject) => {
let sql = `SELECT
id
,cardName
,cardCost
,cardType
,cardAttack
,cardRarity
FROM card
`;
if(cardIds){ sql += 'WHERE card.id IN ('+cardIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
resolve(result);
});
});
return dPromise;
}
function dbGetCardClasses(cardIds = false){
// Get the classes assoc. on each card
const dPromise = new Promise((resolve, reject) => {
let sql = `SELECT
cardId
,classId
FROM card_class
`;
if(cardIds){ sql += 'WHERE cardId IN ('+cardIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
resolve(result);
});
});
return dPromise;
}
function dbGetCardColourRequirement(cardIds = false){
// Get the classes assoc. on each card
const dPromise = new Promise((resolve, reject) => {
let sql = `SELECT
cardId
,colourId
,cost
FROM card_colour_requirement
`;
if(cardIds){ sql += 'WHERE cardId IN ('+cardIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
resolve(result);
});
});
return dPromise;
}
function dbGetCardManaColour(cardIds = false){
// Get the classes assoc. on each card
const cPromise = new Promise((resolve, reject) => {
let sql = `SELECT
cardId
,colourId
FROM card_mana_colour
`;
if(cardIds){ sql += 'WHERE cardId IN ('+cardIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
resolve(result);
});
});
return cPromise;
}
// Effect stuff
function dbGetEffect(cardIds = false){
const ePromise = new Promise((resolve, reject) => {
let sql = `SELECT
cardId
,effectId
,description
FROM card_effect
INNER JOIN effect
ON effect.id = card_effect.effectId
`;
if(cardIds){ sql += 'WHERE cardId IN ('+cardIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
resolve(result);
});
});
return ePromise;
}
function dbGetEffectStep(effectIds = false){
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
`;
if(effectIds){ sql += 'WHERE effectId IN ('+effectIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
resolve(result);
});
});
return ePromise;
}
// Effect Trigger stuff
function dbGetEffectTrigger(effectIds = false){
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
`;
if(effectIds){ sql += 'WHERE effectId IN ('+effectIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
resolve(result);
});
});
return ePromise;
}
// Passive stuff
function dbGetPassive(cardIds = false){
const pPromise = new Promise((resolve, reject) => {
let sql = `SELECT
cardId
,passiveId
FROM card_passive
`;
if(cardIds){ sql += 'WHERE card.id IN ('+cardIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
resolve(result);
});
});
return pPromise;
}
module.exports = {
connect, disconnect
// Testing, and trailing
, dbGetDecks
, dbGetDeckList
, dbGetCards
, dbGetCardClasses
, dbGetCardColourRequirement
, dbGetCardManaColour
, dbGetEffect
, dbGetEffectStep
, dbGetEffectTrigger
, dbGetPassive
};

@ -1,14 +0,0 @@
USE `realms_divided`;
CREATE TABLE IF NOT EXISTS `card_mana_colour` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`cardId` int(11) DEFAULT NULL,
`colourId` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO `card_mana_colour` (`id`, `cardId`, `colourId`) VALUES
(1, 1, 3),
(2, 2, 1),
(3, 3, 2),
(4, 4, 1),
(5, 5, 3);

@ -1,124 +0,0 @@
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');

@ -1,3 +0,0 @@
INSERT INTO `card_passive` (`id`, `cardId`, `passiveId`) VALUES (1, 1, 1);
INSERT INTO `card_passive` (`id`, `cardId`, `passiveId`) VALUES (2, 5, 2);

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

@ -1,206 +0,0 @@
-- --------------------------------------------------------
-- Host: 127.0.0.1
-- Server version: 10.7.8-MariaDB-1:10.7.8+maria~ubu2004 - mariadb.org binary distribution
-- Server OS: debian-linux-gnu
-- HeidiSQL Version: 12.6.0.6765
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-- Dumping database structure for realms_divided
CREATE DATABASE IF NOT EXISTS `realms_divided` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci */;
USE `realms_divided`;
-- Dumping structure for table realms_divided.card
CREATE TABLE IF NOT EXISTS `card` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`cardName` varchar(255) NOT NULL,
`cardCost` tinyint(4) NOT NULL DEFAULT 2,
`cardType` tinyint(4) DEFAULT NULL,
`cardAttack` int(11) DEFAULT NULL,
`cardRarity` tinyint(4) NOT NULL DEFAULT 1,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- Dumping data for table realms_divided.card: ~5 rows (approximately)
INSERT INTO `card` (`id`, `cardName`, `cardCost`, `cardType`, `cardAttack`, `cardRarity`) VALUES
(1, 'Red1', 1, 1, 500, 1),
(2, 'White1', 1, 1, 1000, 1),
(3, 'Blue1', 2, 1, 1000, 1),
(4, 'White 8', 3, 2, NULL, 2),
(5, 'Red7', 2, 2, NULL, 2);
-- Dumping structure for table realms_divided.card_class
CREATE TABLE IF NOT EXISTS `card_class` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`cardId` int(11) DEFAULT NULL,
`classId` smallint(6) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- Dumping data for table realms_divided.card_class: ~4 rows (approximately)
INSERT INTO `card_class` (`id`, `cardId`, `classId`) VALUES
(1, 1, 1),
(2, 2, 1),
(3, 3, 1),
(4, 1, 2);
-- Dumping structure for table realms_divided.card_colour_requirement
CREATE TABLE IF NOT EXISTS `card_colour_requirement` (
`id` tinyint(4) NOT NULL AUTO_INCREMENT,
`cardId` int(11) DEFAULT NULL,
`colourId` tinyint(4) DEFAULT NULL,
`cost` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- Dumping data for table realms_divided.card_colour_requirement: ~5 rows (approximately)
INSERT INTO `card_colour_requirement` (`id`, `cardId`, `colourId`, `cost`) VALUES
(1, 1, 3, 1),
(2, 2, 1, 1),
(3, 3, 2, 1),
(4, 4, 1, 2),
(5, 5, 3, 2);
-- Dumping structure for table realms_divided.card_effect
CREATE TABLE IF NOT EXISTS `card_effect` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`cardId` int(11) DEFAULT NULL,
`effectId` smallint(6) DEFAULT NULL,
`value` smallint(6) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- Dumping data for table realms_divided.card_effect: ~5 rows (approximately)
INSERT INTO `card_effect` (`id`, `cardId`, `effectId`, `value`) VALUES
(1, 1, 2, NULL),
(2, 3, 1, NULL),
(3, 2, 3, NULL),
(4, 4, 4, 1000),
(5, 5, 5, 3000);
-- Dumping structure for table realms_divided.class
CREATE TABLE IF NOT EXISTS `class` (
`id` smallint(6) NOT NULL AUTO_INCREMENT,
`parentId` tinyint(4) DEFAULT NULL,
`className` tinytext NOT NULL,
`primaryColour` smallint(6) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- Dumping data for table realms_divided.class: ~10 rows (approximately)
INSERT INTO `class` (`id`, `parentId`, `className`, `primaryColour`) VALUES
(1, NULL, 'Goblin', 3),
(2, NULL, 'Human', 1),
(3, NULL, 'Spirit', 2),
(4, NULL, 'Warrior', 1),
(5, NULL, 'Orc', 3),
(6, NULL, 'Beast', 5),
(7, NULL, 'Plant', 5),
(8, NULL, 'Undead', 4),
(9, NULL, 'Mechanical', 6),
(10, NULL, 'Void', 7);
-- Dumping structure for table realms_divided.colour
CREATE TABLE IF NOT EXISTS `colour` (
`id` tinyint(4) NOT NULL AUTO_INCREMENT,
`colourName` tinytext DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- Dumping data for table realms_divided.colour: ~7 rows (approximately)
INSERT INTO `colour` (`id`, `colourName`) VALUES
(1, 'White'),
(2, 'Blue'),
(3, 'Red'),
(4, 'Black'),
(5, 'Green'),
(6, 'Brown'),
(7, 'Void');
-- Dumping structure for table realms_divided.deck
CREATE TABLE IF NOT EXISTS `deck` (
`deckId` int(11) NOT NULL,
`playerId` int(11) NOT NULL,
`deckName` tinytext NOT NULL,
PRIMARY KEY (`deckId`,`playerId`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- Dumping data for table realms_divided.deck: ~2 rows (approximately)
INSERT INTO `deck` (`deckId`, `playerId`, `deckName`) VALUES
(1, 1, 'Deck 1 P1'),
(1, 2, 'Deck 1 P2');
-- Dumping structure for table realms_divided.deck_cards
CREATE TABLE IF NOT EXISTS `deck_cards` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`deckId` int(11) DEFAULT NULL,
`playerId` int(11) DEFAULT NULL,
`cardId` int(11) DEFAULT NULL,
`cardCount` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- Dumping data for table realms_divided.deck_cards: ~5 rows (approximately)
INSERT INTO `deck_cards` (`id`, `deckId`, `playerId`, `cardId`, `cardCount`) VALUES
(1, 1, 1, 1, 25),
(2, 1, 1, 5, 10),
(3, 1, 2, 2, 15),
(4, 1, 2, 3, 14),
(5, 1, 2, 4, 6);
-- Dumping structure for table realms_divided.effect
CREATE TABLE IF NOT EXISTS `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;
-- Dumping data for table realms_divided.effect: ~5 rows (approximately)
INSERT INTO `effect` (`id`, `effectName`, `effectDescription`) VALUES
(1, 'Flight', 'Can ignore Taunt, cannot be tagetted by attack'),
(2, 'Reach', 'Can attack Flight units'),
(3, 'Equip', 'Add this cards attack, and effect(s) to another'),
(4, 'Heal', 'Untap X shield(s)'),
(5, 'Hurt', 'Deal X damage to target unit, this combat');
-- Dumping structure for table realms_divided.rarity
CREATE TABLE IF NOT EXISTS `rarity` (
`id` tinyint(4) NOT NULL AUTO_INCREMENT,
`rarityName` tinytext DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- Dumping data for table realms_divided.rarity: ~2 rows (approximately)
INSERT INTO `rarity` (`id`, `rarityName`) VALUES
(1, 'Common'),
(2, 'Uncommon'),
(3, 'Rare');
-- Dumping structure for table realms_divided.type
CREATE TABLE IF NOT EXISTS `type` (
`id` tinyint(4) NOT NULL AUTO_INCREMENT,
`typeName` tinytext DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- Dumping data for table realms_divided.type: ~2 rows (approximately)
INSERT INTO `type` (`id`, `typeName`) VALUES
(1, 'Unit'),
(2, 'Spell'),
(3, 'Token');
/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;

@ -1,25 +0,0 @@
// For anything related to the actual game itself (kinda)
// this will be split into different bits, but should be what manages a rooms
// game states, and alladat
// Basically here to prevent circular dependencies (where I can)
// PlayerId is using array 0,1,2 for now, not the actual id
// actual Id would be better, but the player should be passed correctly
// from the client. They can edit data, but server-side validation SHOULD prevent
// in the future
function passTurn(roomId, playerId){
// Check playerId (not correct atm) before doing the stuff, to verify the user
// IS the user, and in the room
// Test alert so that different data/emits can be sent per-player
global.socketAlert(roomData[roomId].playerData[0].socketId, 'Pass', 'alert');
}
module.exports = {
passTurn
};

@ -1,21 +0,0 @@
{
"name": "cardgame",
"version": "0.0.1",
"description": "Card Game",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/eperezcosano/Uno.git"
},
"author": "Nathan (Aney) Steel",
"license": "???",
"homepage": "anetwork.uk",
"dependencies": {
"express": "^4.21.0",
"mysql": "^2.18.1",
"socket.io": "^4.8.0"
}
}

File diff suppressed because it is too large Load Diff

@ -1,21 +0,0 @@
// 0,1,2 = white,blue,red (for now)
// TODO: Use a DB in future, this is just for testing
let cardArray =
[
{ id: 1, name: 'Red1', colour: 2, cost: 1, type: 'Goblin', atk: 500, rarity: 'common', effect:'[[Sneak]] 500'},
{ id: 2, name: 'Red2', colour: 2, cost: 1, type: 'Goblin', atk: 1500, rarity: 'common', effect:'Cannot attack direct'},
{ id: 3, name: 'Red3', colour: 2, cost: 2, type: 'Goblin', atk: 1000, rarity: 'common', effect:'[[DEATH]] deal 1500 extra to killer'},
{ id: 4, name: 'Red4', colour: 2, cost: 2, type: 'Goblin', atk: 2000, rarity: 'common', effect:null},
{ id: 5, name: 'White1', colour: 0, cost: 1, type: 'Weapon', atk: 500, rarity: 'common', effect:'[[Equip]]'},
{ id: 6, name: 'White2', colour: 0, cost: 2, type: 'Human', atk: 1500, rarity: 'common', effect:null},
{ id: 7, name: 'White3', colour: 0, cost: 2, type: 'Human', atk: 2000, rarity: 'common', effect:'[[TAUNT]]'},
{ id: 8, name: 'White5', colour: 0, cost: 2, type: 'Human', atk: 1500, rarity: 'common', effect:'[[REACH]]'},
{ id: 9, name: 'Blue1', colour: 1, cost: 2, type: 'Spirit', atk: 1000, rarity: 'common', effect:null},
{ id: 10, name: 'Blue3', colour: 1, cost: 2, type: 'Spirit', atk: 1000, rarity: 'common', effect:'[[DRAW]] 1'},
{ id: 11, name: 'Blue4', colour: 1, cost: 2, type: 'Spirit', atk: 1500, rarity: 'common', effect:null},
{ id: 12, name: 'Blue5', colour: 1, cost: 3, type: 'Spirit', atk: 2500, rarity: 'common', effect:'[[FLIGHT]]'}
]
let deckListPlayer = [5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10];
let deckListOpponent = [1,1,1,1,2,2,3,3,4,4,7,7,7,7,5,5,5,3,3,8,8];

@ -1,207 +0,0 @@
// 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();
}

@ -1,680 +0,0 @@
// 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);
}

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

@ -1,133 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/style.css">
<title>cardGame</title>
</head>
<body>
<div class="wrap">
<p>Rooms will not be HTML buttons eventually, but for now...</p>
<button onclick="requestRooms()" class="dib">Get Rooms</button>
<ul id="joinRoomButtons" class="joinRoomButtons dib" style="display:inline;">
</ul>
<button onclick="requestCreateRoom()" style="background:#EEE">Create Room</button>
</div>
<canvas id="canvas" width="1000" height="600"></canvas>
<hr>
<button onclick="passTurn()">Pass Turn</button>
<br><br>
<hr>
<button onclick="untapAllZones()">Untap all</button>
<button onclick="echoCards()">Print cardlist to console</button>
<button onclick="echoCardsInDeck(0)">Print cardsInDeck for player0</button>
<button onclick="echoCardsInDeck(1)">Print cardsInDeck for player1</button>
<hr>
<div>
<button onclick="getItemsAndPrintFrontEnd()">Echo cards: </button>
<select name="boardElementId" id="boardElementId">
<option value="">All</option>
<option value="realDeck">realDeck</option>
<option value="deck">deck</option>
<option value="hand">hand</option>
<option value="mana">mana</option>
<option value="shield">shield</option>
<option value="board">board</option>
<option value="grave">grave</option>
</select>
<select name="playerId" id="playerId">
<option value="">All</option>
<option value="0">Player0</option>
<option value="1">Player1/Opponent</option>
</select>
<input name="listPositionId" id="listPositionId" placeholder="In position 1,2,3..."></input>
<select name="cardStatusId" id="cardStatusId">
<option value="">All</option>
<option value="attacking">Attacking</option>
<option value="tapped">Tapped</option>
</select>
<select name="itemOrCardData" id="itemOrCardData">
<option value="item">Item Data</option>
<option value="card">Card Data</option>
</select>
</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>
<script src="/socket.io/socket.io.js"></script>
<script src="/cards.js"></script><!-- Temp until DB -->
<script src="/shapes.js"></script>
<script src="/main.js"></script>
<script src="/board.js"></script>
<script src="/helper.js"></script>
<script src="/effect.js"></script>
<script src="/debug.js"></script>
</body>
</html>

@ -1,200 +0,0 @@
const socket = io({autoConnect: false});
const canvas = document.getElementById('canvas');;
let room;
let hand = [];
let turn;
let playerName;
// Canvas Initialisation
init();
function init() {
console.log('init');
// Init board here? Or keep in board JS?
document.addEventListener('touchstart', onclick, false);
document.addEventListener('click', onclick, false);
playerName = getCookie('playerName');
if (playerName == null) {
playerName = prompt('Enter your name: ', 'Guest');
if (playerName == null || playerName == "") {
playerName = 'Guest';
}
setCookie('playerName', playerName, 24 * 3600);
}
console.log('>> socket.connect()');
socket.connect();
}
// Cookies are temp, will need logins, etc.
function setCookie(name, value, seconds) {
let date = new Date();
date.setTime(date.getTime() + (seconds * 1000));
let expires = "expires=" + date.toUTCString();
document.cookie = name + "=" + value + ";" + expires + ";path=/";
}
function getCookie(name) {
name += "=";
let cookies = document.cookie.split(';');
for(let i = 0; i < cookies.length; i++) {
let cookie = cookies[i];
while (cookie.charAt(0) == ' ') {
cookie = cookie.substring(1);
}
if (cookie.indexOf(name) == 0) {
return cookie.substring(name.length, cookie.length);
}
}
return null;
}
// Connect
socket.on('connect', connect);
function connect(){
console.log('+ Frontend Connect');
}
// getRooms
function requestRooms(filter = 'all'){
console.log('>> requestRooms:'+filter);
socket.emit('requestRooms', filter);
}
function clearRoomList(){
// Create a list of Rooms
let list = document.getElementById('joinRoomButtons');
// Empty the ul, as to not dupe room buttons, or have rooms that's don't exist
list.innerHTML = "";
}
function returnRooms(data){
clearRoomList();
// Create a list of Rooms
let list = document.getElementById('joinRoomButtons');
let roomCount = Object.keys(data['roomData']).length;
if(roomCount < 1){
alert('No Rooms');
return 0;
}
let rooms = data['roomData'];
// Loops the returned rooms, and add to the list (to be joinable)
for (let room in rooms) {
//console.log(rooms[room].name);
// Making something akin to this:
//<li><button onclick="requestRoom(1)">Room 1</button></li>
let button = document.createElement('button');
button.appendChild(document.createTextNode(rooms[room].name));
button.setAttribute("onclick","requestJoinRoom("+rooms[room].id+");");
let li = document.createElement('li');
li.appendChild(button);
list.appendChild(li);
}
}
socket.on('returnRooms', function (data) {
console.log('<< returnRooms');
returnRooms(data);
});
// createRoom
function requestCreateRoom(){
console.log('+ requestCreateRoom');
socket.emit('requestCreateRoom', playerName);
}
function returnCreateRoom(data){
console.log(data);
if(!data.success){
alert(data.message);
}
}
socket.on('returnCreateRoom', function (data) {
console.log('<< returnCreateRoom');
returnCreateRoom(data);
});
// joinRoom
function requestJoinRoom(roomId) {
console.log('+ requestJoinRoom '.roomId);
socket.emit('requestJoinRoom', playerName, roomId);
room = 0;
hand = [];
turn = false;
console.log('>> Room Request');
}
socket.on('responseJoinRoom', function (name) {
if (name != 'error') {
room = name;
console.log('<< Room Response: ' + name);
//board.drawBoard();
} else {
socket.disconnect();
alert('Rooms are full! Try again later');
}
});
// getCards (TODO: remove if test below is a-okay)
function requestGetCards(deckId, playerId){
console.log('+ requestGetCards');
socket.emit('requestGetCards', deckId, playerId);
}
function responseGetCards(data){
console.log(data);
if(!data.success){
alert(data.message);
}
}
socket.on('responseGetCards', function (data) {
console.log('<< responseGetCards');
responseGetCards(data);
});
// When game starts, loadBoard to add data for clients
// and display the starting board
function responseStartGame(data){
if(!data.success){
alert(data.message);
return false;
}
return data;
}
socket.on('responseStartGame', function (data) {
console.log('<< responseStartGame');
responseStartGame(data);
if(data.success !== true){
alert('Err with responseStartGame. '+data.message);
}
// Pass only the data to loadBoard
loadBoard(data.message);
});
// ALERTS
socket.on('alert', function (data) {
console.log('<< alert');
alert(data.message);
});
// GAME SERVER STUFF
// PASS TURN
function passTurn(){
// TODO: Use itemData.player/itemData.room or whatnot here
console.log(roomId);
let playerId = prompt('PlayerId 0/1', 0); // TODO: very temp, will be playerId/arrayId
console.log('+ passTurn');
socket.emit('passTurn', roomId, playerId);
}

@ -1,146 +0,0 @@
// https://stackoverflow.com/a/29676404
context = document.getElementById("canvas").getContext("2d");
let defaultFillStyle = '#000';
let shapeDebug = true;
let shapeDebugColour = '#FF00FF';
class Shape extends Path2D{
constructor(params){
super();
this.shape = params.shape || 'rectangle';
this.name = params.name;
this.x = params.x || 0;
this.y = params.y || 0;
this.width = params.width || 0;
this.height = params.height || 0;
this.fillStyle = params.fillStyle || "#FFFFFF";
this.strokeStyle = params.strokeStyle || false;
this.lineWidth = params.lineWidth || 0;
this.shadow = params.shadow || false;
}
setShadow(shadow){
this.shadow = shadow;
}
draw(){
//console.log('Draw Shape: '+this.name);
//console.log('X: '+this.x+' Y: '+this.y);
//console.log('W: '+this.width+' H: '+this.height);
//console.log('');
if (this.fillStyle) {
context.fillStyle = this.fillStyle;
if(this.shadow){
context.shadowColor = "#333";
context.shadowOffsetX = 1;
context.shadowOffsetY = 3;
context.shadowBlur = 10;
}
if(this.shape == 'circle'){
// X,Y,Radius, start, end
context.beginPath();
context.arc(this.x, this.y, this.width/2, 0, 2 * Math.PI);
context.fill();
context.closePath();
}else if(this.shape == 'semi'){
context.beginPath();
context.arc(this.x, this.y, this.width/2, Math.PI, 0);
context.fill();
context.closePath();
}else if (this.shape == 'rectangle'){
context.fillRect(this.x, this.y, this.width, this.height);
}
context.fillStyle = defaultFillStyle; // Reset back to default
context.shadowColor = 'transparent';
context.shadowBlur = null;
context.shadowOffsetX = null;
context.shadowOffsetY = null;
}
if (this.strokeStyle && this.lineWidth || shapeDebug) {
context.strokeStyle = this.strokeStyle;
context.lineWidth = this.lineWidth;
context.lineWidth = 2;
if(!this.strokeStyle && shapeDebug){
context.strokeStyle = shapeDebugColour;
}
if(this.shape == 'circle'){
// X,Y,Radius, start, end
context.beginPath();
context.arc(this.x, this.y, this.width/2, 0, 2 * Math.PI);
context.stroke();
context.closePath();
}else if(this.shape == 'semi'){
context.beginPath();
context.arc(this.x, this.y, this.width/2, Math.PI, 0);
context.stroke();
context.closePath();
}else if (this.shape == 'rectangle'){
context.strokeRect(this.x, this.y, this.width, this.height);
}
else if (this.shape == 'unit'){
context.beginPath();
context.arc(this.x, this.y, this.width/2, Math.PI, 0);
// Start at bottom left of the semi
context.moveTo(this.x-this.width/2, this.y);
// Draw accross to bottom right of semi
context.lineTo(this.x+this.width/2, this.y);
// Draw down to the desired height
context.lineTo(this.x+this.width/2, this.y+this.height/3);
// Draw accross to that height, but aligned to left of semi
context.lineTo(this.x-this.width/2, this.y+this.height/3);
context.stroke();
context.closePath();
}
context.strokeStyle = defaultFillStyle;
}
}
startClip(shape = null){
// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clip#creating_a_complex_clipping_region
if(this.shape == 'circle'){
// X,Y,Radius, start, end
context.beginPath();
context.arc(this.x, this.y, this.width/2, 0, 2 * Math.PI);
context.fill();
context.closePath();
}else if(this.shape == 'semi'){
context.beginPath();
context.arc(this.x, this.y, this.width/2, Math.PI, 0);
context.fill();
context.closePath();
}else if (this.shape == 'rectangle'){
context.fillRect(this.x, this.y, this.width, this.height);
}
// This is one of the shapes for the card images to sit it
// TODO: Will be: unit,token,spell, etc. ALSO will have each shape for UI elements too
else if (this.shape == 'unit'){
context.beginPath();
context.arc(this.x, this.y, this.width/2, Math.PI, 0);
// Start at bottom left of the semi
context.moveTo(this.x-this.width/2, this.y);
// Draw accross to bottom right of semi
context.lineTo(this.x+this.width/2, this.y);
// Draw down to the desired height
context.lineTo(this.x+this.width/2, this.y+this.height/3);
// Draw accross to that height, but aligned to left of semi
context.lineTo(this.x-this.width/2, this.y+this.height/3);
context.fill();
context.closePath();
}
ctx.save(); // Save the canvas draw before the clip is applied
context.clip();
}
endClip(){
ctx.restore(); // Restore the canvas draw post clip applied, to get everything else back too
}
}

@ -1,24 +0,0 @@
html,body{
margin: 0;
padding: 0;
background-color: #a1abaa;
}
canvas{
margin: auto;
display: block;
}
.wrap{
margin: auto;
display: block;
width: 1000px;
}
.dib{display: inline-block; margin: 0; margin-bottom: 8px;}
.joinRoomButtons li{
display: inline-block;
margin-left: 6px;
}

@ -1,110 +0,0 @@
// Build a room, fill will players, etc.
const cardGen = require('./cardGen');
const components = require('./components');
// 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(playerData, itemData){
itemData.player = {}; //let player = {}; // Player item belongs to
itemData.players = []; // List of the players (an associated playerItem?)
let playerNo = 0 + itemData['itemCount']; // Start loop from current itemCount
playerCount = playerData.length + itemData['itemCount']; // End at playerCount diff from itemCount
let i = 0;
for(playerNo; playerNo < playerCount; playerNo++){
itemData['players'].push([playerNo, playerData[i]]); // Add player no to array so can be looped
i++;
}
return itemData;
}
// For future, when 2v2s, and 5v1 Raids, etc.
function setTeams(){
}
function roomGeneration(roomId){
return new Promise((resolve, reject) => {
(async () => {
// Player's sockets
console.log('--- Room for generation ---');
console.log(io.sockets.adapter.rooms.get(roomId));
let itemData = startItemCount();
// Player data with Sockets
let playerData = [];
let playerOrder = {}; // Need a better name
let i = 1;
let clients = global.io.sockets.adapter.rooms.get(roomId);
for (const clientId of clients) {
const clientSocket = global.io.sockets.sockets.get(clientId);
// Which order the player is? Just using the array
playerOrder[clientSocket.playerId] = playerData.length;
playerData.push({
'playerDataId': playerData.length
,'playerId': clientSocket.playerId
,'deck':{'playerId':i,'deckId':1}
,'socketId': clientSocket.id // TODO: ONLY FOR SERVERSIDE!!!
});
i++;
}
// Add players for the room (seperate to playerData, currently what's used)
// ??
itemData = setPlayers(playerData, itemData);
// TODO: Get their selected decks
// Add all the empty components to the room itemData
itemData.component = components.component;
// Generate the decks, and card within the deck cardLists
[itemData] = await Promise.all([ cardGen.requestDeck(itemData) ]);
// Some room stuff, likely change this
itemData.roomId = roomId;
itemData.turn = 0; // The turn count of the match
itemData.playersTurn = 0; // This means it's playerData[0] turn
// Room has just been created, so add the itemData and playerData to the room
// on server-side so it's easily accessible
roomData[roomId].itemData = itemData;
roomData[roomId].playerData = playerData;
roomData[roomId].playerOrder = playerOrder;
// Return the all the itemData to the client(s)
// TODO: This will need to give different data for each, or at least
// to differ the boardside
return resolve(itemData);
})()
});
}
// TODO: disconnect, reconnect, resume
module.exports = {
startItemCount
,setPlayers
,roomGeneration
};

@ -1,229 +0,0 @@
const roomMod = require('./roomMod');
// Variables for server overall
let numRooms = 0;
const maxRooms = 3;
const maxPlayersPerRoom = 2;
const maxSpectatorsPerRoom = 0;
function requestRooms(socket, filter){
console.log('+ requestRooms recieved');
console.log('- filter: '+filter);
let response = getRooms(filter, dump = true);
global.io.to(socket.id).emit('returnRooms', response);
console.log('');
}
function getRooms(filter = 'all', dump = false){
console.log('+ getRooms');
let response = {
random: 'randomStuff',
roomData: global.roomData,
};
if(dump){
console.log(response);
console.log('');
}
return response;
}
function requestCreateRoom(socket, playerName){
console.log('+ createRoom recieved');
console.log('- requested by: '+playerName);
response = createRoom(roomId = false, dump = true);
global.io.to(socket.id).emit('returnCreateRoom', response);
if(response.success){
let response = getRooms(filter = 'all', dump = true);
global.io.to(socket.id).emit('returnRooms', response);
}
console.log('');
}
function createRoom(roomId = false, dump = true){
let roomName = false;
if(roomId == false){
roomId = numRooms + 1;
}
console.log(roomId);
let response = {
success: false,
message: 'No idea bossman'
};
// Max room limit reached
console.log(numRooms);
console.log(maxRooms);
if(numRooms >= maxRooms){
console.log('- Room limit reached');
response = {
success: false,
message: 'No space '+numRooms+' out of '+maxRooms+' created.'
};
// Create room
}else{
console.log('- Creating room')
let room = {};
room['id'] = roomId;
room['name'] = 'Room:'+room['id'];
roomName = room['name'];
room['password'] = '';
room['timeout'] = {};
room['timeout']['s'] = 10;
room['people'] = 0;
room['playerIds'] = {};
global.roomData[roomId] = room;
numRooms = numRooms + 1;
response = {
success: true,
message: 'Room Created: '+roomName,
};
}
if(dump){
console.log(response);
console.log('');
}
return response;
}
function requestJoinRoom(socket, playerName, roomId){
console.log('+ requestJoinRoom recieved');
let room = global.roomData[roomId];
// https://stackoverflow.com/a/18096649
socket.playerId = playerName;
if(room === undefined){
console.log('>> Room does not exist');
return 'error';
}
let roomName = 'Room_' + roomId;
let people = room['people'];
if(isUserInRoom(playerName, roomId)){
console.log('>> Already in room');
return 'already in room';
}
if (people < maxPlayersPerRoom) {
// Update people in room count
people = room['people'] += 1;
// Add playerId to room (playerName for now while Ids don't exist TODO)
room['playerIds'][playerName] = playerName;
// https://socket.io/docs/v4/rooms/
// https://stackoverflow.com/a/25028953
socket.join(roomId);
console.log('>> User ' + playerName +
' connected on ' + roomName + ' (' + (people) + '/' + maxPlayersPerRoom + ')');
// Joined room (emit to the player that just joined)
global.io.to(socket.id).emit('responseRoom', response);
if (people >= maxPlayersPerRoom) {
console.log('- starting game');
// startGame for room
startGame(roomId);
}
}
}
// Will need to be different to playerName in future (in case dupes)
// would use playerId TODO
function isUserInRoom(playerName, roomId){
if(playerName in global.roomData[roomId]['playerIds']){
return true;
}
return false;
}
async function startGame(roomId){
console.log('>> Room: ' + roomId + ': Requesting game...');
let people = global.roomData[roomId].players;
/*
try {
//people = io.sockets.adapter.rooms.get(roomId).size;
} catch (e) {
console.log('>> Room: ' + roomId + ': No people here...');
return;
}
*/
// For now, if there's 2 people only. Will need changing for
// 3v1, 5v1, 2v2, etc...
let response = {success: false, message: 'Failed requestStartGame() server.js'};
if(people < maxPlayersPerRoom){
console.log('Too few people');
}
console.log('>> Room: ' + roomId + ': Starting');
// https://stackoverflow.com/a/25028953
//console.log(util.inspect(io.sockets.adapter.rooms.get(roomId), true, 4, true))
let clients = global.io.sockets.adapter.rooms.get(roomId);
// This should return the deck data, etc. for each client
// ideally only returning the items that the user can/should
// see i.e. shouldn't give them the inDeck card list just a counter
// shouldn't have opponent card data/their hand shouldn't be flipped
// Not sure how to catch errors for these await alls
// TODO: Look into error handling for await alls
const [itemData] =
await Promise.all([
roomMod.roomGeneration(roomId),
]);
// data is the 'itemData' not all the roomData
response.success = true;
response.message = itemData;
// Each player then gets sent the roomGeneration stuff
for (const clientId of clients) {
const clientSocket = global.io.sockets.sockets.get(clientId);
console.log('>> responseStartGame: '+clientSocket.playerId);
// TODO: TESTING STUFF, REMOVE WHEN SORTED
let message = 'You are player: '+roomData[roomId].playerOrder[clientSocket.playerId];
global.socketAlert(clientSocket.id, message, 'alert');
// Emit the itemData to client socket (TODO: only emit what each player should see/recieve)
global.io.to(clientSocket.id).emit('responseStartGame', response);
}
}
// TODO: Need a 'leave room'/disconnect
module.exports = {
requestRooms
,requestJoinRoom
,requestCreateRoom
};

@ -1,66 +0,0 @@
const express = require('express');
const database = require('./database');
const rooms = require('./rooms');
const gameMod = require('./gameMod');
const app = express();
const http = require('http').Server(app);
const port = process.env.PORT || 3000;
const io = require('socket.io')(http);
global.io = io;
// To log the player sockets, so they can be easily referred to
// maybe jank, but can't see alternative currently
global.playerSocket = {};
global.roomData = {}; // Made global for now, as to not replicate. Maybe sub-optimal?
// util is what nodejs uses for console.log, but has a depth of 2 set
// so console.logs show [Array]/[Object] instead of useful info.
// This can be overridden console.log(util.inspect(LOGDATA, true, 4, true))
// 4 being new depth, true (last one) is to show colours
const util = require('util')
app.use(express.static(__dirname + '/public'));
http.listen(port, () => console.log('listening on port ' + port));
database.connect();
io.on('connection', onConnection);
function onConnection(socket){
console.log('+ User connected');
console.log('');
// Rooms (joining, creating, etc)
socket.on('requestRooms', function(filter) {
rooms.requestRooms(socket, filter);
});
socket.on('requestJoinRoom', function(playerName, roomId) {
rooms.requestJoinRoom(socket, playerName, roomId);
});
socket.on('requestCreateRoom', function(playerName) {
rooms.requestCreateRoom(socket, playerName);
});
// Game (actual things relating to the game)
// The socket should only be in one game, so socket.on should
// do this, but passing room/player anyways as it's how I've written some
// roomData bits. TODO: Look if I can do this better...
socket.on('passTurn', function(roomId, playerId) {
gameMod.passTurn(roomId, playerId);
});
}
// Globals for easier clientside alerts/logs, etc.
global.socketAlert = function(socket, message, type = 'alert'){
global.io.to(socket).emit(
type, {'message': message}
);
}
Loading…
Cancel
Save