From 92385bb72dc2a4e5303170eea92705fcbe4f4927 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Thu, 6 Jun 2019 06:44:16 +1000 Subject: [PATCH] BUGFIX: train, untrain, purchase, sell while spying --- common/utilities.js | 4 + server/equipment.js | 200 +++++++++++++++++++++------------------ server/profiles.js | 224 ++++++++++++++++++++++++-------------------- 3 files changed, 236 insertions(+), 192 deletions(-) diff --git a/common/utilities.js b/common/utilities.js index 2a34149..fcac34e 100644 --- a/common/utilities.js +++ b/common/utilities.js @@ -24,8 +24,12 @@ let excluded = [ //messages that should not be logged 'Can\'t train while attacking', 'Can\'t untrain while attacking', + 'Can\'t train while spying', + 'Can\'t untrain while spying', 'Can\'t purchase while attacking', 'Can\'t sell while attacking', + 'Can\'t purchase while spying', + 'Can\'t sell while spying', 'Purchase made', 'Sale made', diff --git a/server/equipment.js b/server/equipment.js index dac4e83..68b8049 100644 --- a/server/equipment.js +++ b/server/equipment.js @@ -4,7 +4,7 @@ require('dotenv').config(); //utilities let { log } = require('../common/utilities.js'); -let { getStatistics, getOwned, isAttacking } = require('./utilities.js'); +let { getStatistics, getOwned, isAttacking, isSpying } = require('./utilities.js'); const equipmentRequest = (connection) => (req, res) => { //validate the credentials @@ -95,81 +95,91 @@ const purchaseRequest = (connection) => (req, res) => { return; } - //get the player's gold - let query = 'SELECT gold, scientists FROM profiles WHERE accountId = ?;'; - connection.query(query, [req.body.id], (err, results) => { + isSpying(connection, req.body.id, (err, spying) => { if (err) throw err; - //just in case - if (results.length === 0) { - res.status(400).write(log('Purchase made on unrecognized account', req.body.id, req.body.token)); + if (spying) { + res.status(400).write(log('Can\'t purchase while spying', req.body.id, req.body. token, req.body.type, req.body.name)); res.end(); return; } - //get the stats for all objects - getStatistics((err, { statistics }) => { + //get the player's gold + let query = 'SELECT gold, scientists FROM profiles WHERE accountId = ?;'; + connection.query(query, [req.body.id], (err, results) => { if (err) throw err; - //valid parameters - if(!statistics[req.body.type] || !statistics[req.body.type][req.body.name]) { - res.status(400).write(log('Invalid equipment purchase parameters', req.body.id, req.body.token, req.body.type, req.body.name)); + //just in case + if (results.length === 0) { + res.status(400).write(log('Purchase made on unrecognized account', req.body.id, req.body.token)); res.end(); return; } - //enough gold? - if (results[0].gold < statistics[req.body.type][req.body.name].cost) { - res.status(400).write(log('Not enough gold', req.body.id, req.body.token, req.body.type, req.body.name)); - res.end(); - return; - } - - //for sale? - if (!statistics[req.body.type][req.body.name].visible || !statistics[req.body.type][req.body.name].purchasable) { - res.status(400).write(log('Item not for sale', req.body.id, req.body.token, req.body.type, req.body.name)); - res.end(); - return; - } - - //high enough level? - if (results[0].scientists < statistics[req.body.type][req.body.name].scientistsRequired) { - res.status(400).write(log('Not enough scientists', req.body.id, req.body.token, req.body.type, req.body.name)); - res.end(); - return; - } - - //purchase approved. - - //get the user's current item data (including quantity) - let query = 'SELECT * FROM equipment WHERE accountId = ? AND name = ?;'; - connection.query(query, [req.body.id, req.body.name], (err, results) => { + //get the stats for all objects + getStatistics((err, { statistics }) => { if (err) throw err; - //add to or update the record - let query; - if (results.length > 0) { - query = 'UPDATE equipment SET quantity = quantity + 1 WHERE accountId = ? AND name = ? AND type = ?;'; - } else { - query = 'INSERT INTO equipment (accountId, name, type, quantity) VALUES (?, ?, ?, 1);'; + //valid parameters + if(!statistics[req.body.type] || !statistics[req.body.type][req.body.name]) { + res.status(400).write(log('Invalid equipment purchase parameters', req.body.id, req.body.token, req.body.type, req.body.name)); + res.end(); + return; } - connection.query(query, [req.body.id, req.body.name, req.body.type], (err) => { + //enough gold? + if (results[0].gold < statistics[req.body.type][req.body.name].cost) { + res.status(400).write(log('Not enough gold', req.body.id, req.body.token, req.body.type, req.body.name)); + res.end(); + return; + } + + //for sale? + if (!statistics[req.body.type][req.body.name].visible || !statistics[req.body.type][req.body.name].purchasable) { + res.status(400).write(log('Item not for sale', req.body.id, req.body.token, req.body.type, req.body.name)); + res.end(); + return; + } + + //high enough level? + if (results[0].scientists < statistics[req.body.type][req.body.name].scientistsRequired) { + res.status(400).write(log('Not enough scientists', req.body.id, req.body.token, req.body.type, req.body.name)); + res.end(); + return; + } + + //purchase approved. + + //get the user's current item data (including quantity) + let query = 'SELECT * FROM equipment WHERE accountId = ? AND name = ?;'; + connection.query(query, [req.body.id, req.body.name], (err, results) => { if (err) throw err; - //remove gold from the user's account - let query = 'UPDATE profiles SET gold = gold - ? WHERE accountId = ?;'; - connection.query(query, [statistics[req.body.type][req.body.name].cost, req.body.id], (err) => { + //add to or update the record + let query; + if (results.length > 0) { + query = 'UPDATE equipment SET quantity = quantity + 1 WHERE accountId = ? AND name = ? AND type = ?;'; + } else { + query = 'INSERT INTO equipment (accountId, name, type, quantity) VALUES (?, ?, ?, 1);'; + } + + connection.query(query, [req.body.id, req.body.name, req.body.type], (err) => { if (err) throw err; - //return the new owned data - getOwned(connection, req.body.id, (err, results) => { + //remove gold from the user's account + let query = 'UPDATE profiles SET gold = gold - ? WHERE accountId = ?;'; + connection.query(query, [statistics[req.body.type][req.body.name].cost, req.body.id], (err) => { if (err) throw err; - res.status(200).json(Object.assign(results)); - res.end(); + //return the new owned data + getOwned(connection, req.body.id, (err, results) => { + if (err) throw err; - log('Purchase made', req.body.id, req.body.token, req.body.type, req.body.name); + res.status(200).json(Object.assign(results)); + res.end(); + + log('Purchase made', req.body.id, req.body.token, req.body.type, req.body.name); + }); }); }); }); @@ -202,65 +212,75 @@ const sellRequest = (connection) => (req, res) => { return; } - //get the player's item quantity - let query = 'SELECT * FROM equipment WHERE accountId = ? AND type = ? AND name = ?;'; - connection.query(query, [req.body.id, req.body.type, req.body.name], (err, results) => { + isSpying(connection, req.body.id, (err, spying) => { if (err) throw err; - if (results.length === 0) { - res.status(400).write(log('Can\'t sell something you don\'t own', req.body.id, req.body. token, req.body.type, req.body.name)); + if (spying) { + res.status(400).write(log('Can\'t sell while spying', req.body.id, req.body. token, req.body.type, req.body.name)); res.end(); return; } - //get the stats for all objects - getStatistics((err, { statistics }) => { + //get the player's item quantity + let query = 'SELECT * FROM equipment WHERE accountId = ? AND type = ? AND name = ?;'; + connection.query(query, [req.body.id, req.body.type, req.body.name], (err, results) => { if (err) throw err; - //valid parameters - if(!statistics[req.body.type] || !statistics[req.body.type][req.body.name]) { - res.status(400).write(log('Invalid equipment sell parameters', req.body.id, req.body.token, req.body.type, req.body.name)); + if (results.length === 0) { + res.status(400).write(log('Can\'t sell something you don\'t own', req.body.id, req.body. token, req.body.type, req.body.name)); res.end(); return; } - //for sale? - if (!statistics[req.body.type][req.body.name].saleable) { - res.status(400).write(log('Item can\'t be sold', req.body.id, req.body.token, req.body.type, req.body.name)); - res.end(); - return; - } - - //sale approved. - - //add gold to the user's account - let query = 'UPDATE profiles SET gold = gold + ? WHERE accountId = ?;'; - connection.query(query, [Math.floor(statistics[req.body.type][req.body.name].cost/2), req.body.id], (err) => { + //get the stats for all objects + getStatistics((err, { statistics }) => { if (err) throw err; - //remove the item from the inventory - let query = 'UPDATE equipment SET quantity = quantity - 1 WHERE id = ?;'; - connection.query(query, [results[0].id], (err) => { + //valid parameters + if(!statistics[req.body.type] || !statistics[req.body.type][req.body.name]) { + res.status(400).write(log('Invalid equipment sell parameters', req.body.id, req.body.token, req.body.type, req.body.name)); + res.end(); + return; + } + + //for sale? + if (!statistics[req.body.type][req.body.name].saleable) { + res.status(400).write(log('Item can\'t be sold', req.body.id, req.body.token, req.body.type, req.body.name)); + res.end(); + return; + } + + //sale approved. + + //add gold to the user's account + let query = 'UPDATE profiles SET gold = gold + ? WHERE accountId = ?;'; + connection.query(query, [Math.floor(statistics[req.body.type][req.body.name].cost/2), req.body.id], (err) => { if (err) throw err; - //return the new owned data - getOwned(connection, req.body.id, (err, results) => { + //remove the item from the inventory + let query = 'UPDATE equipment SET quantity = quantity - 1 WHERE id = ?;'; + connection.query(query, [results[0].id], (err) => { if (err) throw err; - res.status(200).json(Object.assign(results)); - res.end(); - - log('Sale made', req.body.id, req.body.token, req.body.type, req.body.name); - - //Extra: clean the database - let query = 'DELETE FROM equipment WHERE quantity <= 0;'; - connection.query(query, (err) => { + //return the new owned data + getOwned(connection, req.body.id, (err, results) => { if (err) throw err; - log('Cleaned database', 'equipment sale'); + res.status(200).json(Object.assign(results)); + res.end(); + + log('Sale made', req.body.id, req.body.token, req.body.type, req.body.name); + + //Extra: clean the database + let query = 'DELETE FROM equipment WHERE quantity <= 0;'; + connection.query(query, (err) => { + if (err) throw err; + + log('Cleaned database', 'equipment sale'); + }); }); }); - }) + }); }); }); }); diff --git a/server/profiles.js b/server/profiles.js index 2652809..865cd85 100644 --- a/server/profiles.js +++ b/server/profiles.js @@ -4,7 +4,7 @@ require('dotenv').config(); //libraries let CronJob = require('cron').CronJob; -let { isAttacking } = require('./utilities.js'); +let { isAttacking, isSpying } = require('./utilities.js'); //utilities let { logDiagnostics } = require('./diagnostics.js'); @@ -189,67 +189,77 @@ const trainRequest = (connection) => (req, res) => { return; } - //determine the cost of the training TODO: make these global for the client too - let cost = 0; - switch(req.body.role) { - case 'soldier': - cost = 100; - break; - - case 'spy': - cost = 300; - break; - - case 'scientist': - cost = 120; - break; - } - - //verify that the user has a high enough gold and recruit balance - let query = 'SELECT recruits, gold FROM profiles WHERE accountId = ?;'; - connection.query(query, [req.body.id], (err, results) => { + isSpying(connection, req.body.id, (err, spying) => { if (err) throw err; - if (results[0].recruits <= 0) { - res.status(400).write(log('Not enough recruits', results[0].recruits, req.body.id, req.body.token)); + if (spying) { + res.status(400).write(log('Can\'t train while spying', req.body.id)); res.end(); return; } - if (results[0].gold < cost) { - res.status(400).write(log('Not enough gold', results[0].gold, req.body.id, req.body.token)); - res.end(); - return; + //determine the cost of the training TODO: make these global for the client too + let cost = 0; + switch(req.body.role) { + case 'soldier': + cost = 100; + break; + + case 'spy': + cost = 300; + break; + + case 'scientist': + cost = 120; + break; } - //update the profile with new values (NOTE: extra protection for network latency) - let query = 'UPDATE profiles SET gold = gold - ?, recruits = recruits - 1, soldiers = soldiers + ?, spies = spies + ?, scientists = scientists + ? WHERE accountId = ? AND gold >= ? AND recruits > 0;'; - connection.query(query, [cost, req.body.role === 'soldier' ? 1 : 0, req.body.role === 'spy' ? 1 : 0, req.body.role === 'scientist' ? 1 : 0, req.body.id, cost], (err) => { + //verify that the user has a high enough gold and recruit balance + let query = 'SELECT recruits, gold FROM profiles WHERE accountId = ?;'; + connection.query(query, [req.body.id], (err, results) => { if (err) throw err; - //send the new profile data as JSON (NOTE: possible duplication) - let query = 'SELECT username, profiles.* FROM profiles JOIN accounts ON accounts.id = profiles.accountId WHERE accounts.id = ?;'; - connection.query(query, [req.body.id], (err, results) => { + if (results[0].recruits <= 0) { + res.status(400).write(log('Not enough recruits', results[0].recruits, req.body.id, req.body.token)); + res.end(); + return; + } + + if (results[0].gold < cost) { + res.status(400).write(log('Not enough gold', results[0].gold, req.body.id, req.body.token)); + res.end(); + return; + } + + //update the profile with new values (NOTE: extra protection for network latency) + let query = 'UPDATE profiles SET gold = gold - ?, recruits = recruits - 1, soldiers = soldiers + ?, spies = spies + ?, scientists = scientists + ? WHERE accountId = ? AND gold >= ? AND recruits > 0;'; + connection.query(query, [cost, req.body.role === 'soldier' ? 1 : 0, req.body.role === 'spy' ? 1 : 0, req.body.role === 'scientist' ? 1 : 0, req.body.id, cost], (err) => { if (err) throw err; - //check just in case - if (results.length !== 1) { - res.status(400).write(log('Invalid recruit credentials - 2', req.body.id, req.body.token)); - res.end(); - return; - } + //send the new profile data as JSON (NOTE: possible duplication) + let query = 'SELECT username, profiles.* FROM profiles JOIN accounts ON accounts.id = profiles.accountId WHERE accounts.id = ?;'; + connection.query(query, [req.body.id], (err, results) => { + if (err) throw err; - //results.length === 1 - res.status(200).json({ - username: results[0].username, - gold: results[0].gold, - recruits: results[0].recruits, - soldiers: results[0].soldiers, - spies: results[0].spies, - scientists: results[0].scientists + //check just in case + if (results.length !== 1) { + res.status(400).write(log('Invalid recruit credentials - 2', req.body.id, req.body.token)); + res.end(); + return; + } + + //results.length === 1 + res.status(200).json({ + username: results[0].username, + gold: results[0].gold, + recruits: results[0].recruits, + soldiers: results[0].soldiers, + spies: results[0].spies, + scientists: results[0].scientists + }); + res.end(); + log('Train executed', results[0].username, req.body.role, req.body.id, req.body.token); }); - res.end(); - log('Train executed', results[0].username, req.body.role, req.body.id, req.body.token); }); }); }); @@ -286,72 +296,82 @@ const untrainRequest = (connection) => (req, res) => { return; } - //verify that the user has a high enough balance - let query = 'SELECT soldiers, spies, scientists FROM profiles WHERE accountId = ?;'; - connection.query(query, [req.body.id], (err, results) => { + isSpying(connection, req.body.id, (err, spying) => { if (err) throw err; - if (req.body.role === 'soldier' && results[0].soldiers <= 0) { - res.status(400).write(log('Not enough soldiers', results[0].soldiers, req.body.id, req.body.token)); + if (spying) { + res.status(400).write(log('Can\'t untrain while spying', req.body.id, req.body.token)); res.end(); return; } - if (req.body.role === 'spy' && results[0].spies <= 0) { - res.status(400).write(log('Not enough spies', results[0].spies, req.body.id, req.body.token)); - res.end(); - return; - } - - if (req.body.role === 'scientist' && results[0].scientists <= 0) { - res.status(400).write(log('Not enough scientists', results[0].scientists, req.body.id, req.body.token)); - res.end(); - return; - } - - //hacky - let roleName = null; - - if (req.body.role === 'soldier') { - roleName = 'soldiers'; - } else if (req.body.role === 'spy') { - roleName = 'spies'; - } else if (req.body.role === 'scientist') { - roleName = 'scientists'; - } else { - res.status(400).write(log('Unknown role received', req.body.role, req.body.id, req.body.token)); - res.end(); - return; - } - - //update the profile with new values (NOTE: extra protection for network latency) - let query = `UPDATE profiles SET recruits = recruits + 1, soldiers = soldiers - ?, spies = spies - ?, scientists = scientists - ? WHERE accountId = ? AND ${roleName} > 0;`; - connection.query(query, [roleName === 'soldiers' ? 1 : 0, roleName === 'spies' ? 1 : 0, roleName === 'scientists' ? 1 : 0, req.body.id], (err) => { + //verify that the user has a high enough balance + let query = 'SELECT soldiers, spies, scientists FROM profiles WHERE accountId = ?;'; + connection.query(query, [req.body.id], (err, results) => { if (err) throw err; - //send the new profile data as JSON (NOTE: possible duplication) - let query = 'SELECT username, profiles.* FROM profiles JOIN accounts ON accounts.id = profiles.accountId WHERE accounts.id = ?;'; - connection.query(query, [req.body.id], (err, results) => { + if (req.body.role === 'soldier' && results[0].soldiers <= 0) { + res.status(400).write(log('Not enough soldiers', results[0].soldiers, req.body.id, req.body.token)); + res.end(); + return; + } + + if (req.body.role === 'spy' && results[0].spies <= 0) { + res.status(400).write(log('Not enough spies', results[0].spies, req.body.id, req.body.token)); + res.end(); + return; + } + + if (req.body.role === 'scientist' && results[0].scientists <= 0) { + res.status(400).write(log('Not enough scientists', results[0].scientists, req.body.id, req.body.token)); + res.end(); + return; + } + + //hacky + let roleName = null; + + if (req.body.role === 'soldier') { + roleName = 'soldiers'; + } else if (req.body.role === 'spy') { + roleName = 'spies'; + } else if (req.body.role === 'scientist') { + roleName = 'scientists'; + } else { + res.status(400).write(log('Unknown role received', req.body.role, req.body.id, req.body.token)); + res.end(); + return; + } + + //update the profile with new values (NOTE: extra protection for network latency) + let query = `UPDATE profiles SET recruits = recruits + 1, soldiers = soldiers - ?, spies = spies - ?, scientists = scientists - ? WHERE accountId = ? AND ${roleName} > 0;`; + connection.query(query, [roleName === 'soldiers' ? 1 : 0, roleName === 'spies' ? 1 : 0, roleName === 'scientists' ? 1 : 0, req.body.id], (err) => { if (err) throw err; - //check just in case - if (results.length !== 1) { - res.status(400).write(log('Invalid untrain credentials - 2', req.body.role, req.body.id, req.body.token)); - res.end(); - return; - } + //send the new profile data as JSON (NOTE: possible duplication) + let query = 'SELECT username, profiles.* FROM profiles JOIN accounts ON accounts.id = profiles.accountId WHERE accounts.id = ?;'; + connection.query(query, [req.body.id], (err, results) => { + if (err) throw err; - //results.length === 1 - res.status(200).json({ - username: results[0].username, - gold: results[0].gold, - recruits: results[0].recruits, - soldiers: results[0].soldiers, - spies: results[0].spies, - scientists: results[0].scientists + //check just in case + if (results.length !== 1) { + res.status(400).write(log('Invalid untrain credentials - 2', req.body.role, req.body.id, req.body.token)); + res.end(); + return; + } + + //results.length === 1 + res.status(200).json({ + username: results[0].username, + gold: results[0].gold, + recruits: results[0].recruits, + soldiers: results[0].soldiers, + spies: results[0].spies, + scientists: results[0].scientists + }); + res.end(); + log('Untrain executed', results[0].username, roleName, req.body.id, req.body.token); }); - res.end(); - log('Untrain executed', results[0].username, roleName, req.body.id, req.body.token); }); }); });